From 960eb792acde51e3e0b862c19d58acaf3082c500 Mon Sep 17 00:00:00 2001 From: Mohammed Sameer Date: Mon, 15 Jul 2013 02:45:23 +0300 Subject: [PATCH] Initial ui reimplementation. Still in its early phase. --- qml/CameraOverlay.qml | 75 +++ qml/CameraSettings.qml | 138 ++--- qml/CameraToolBar.qml | 157 +++--- qml/CameraView.qml | 266 +++++++++ qml/CaptureButton.qml | 63 ++- qml/FocusReticle.qml | 370 ++++++------- qml/ImageOverlay.qml | 255 +++++++++ qml/ImagePage.qml | 278 ---------- qml/ImageResolutionSettings.qml | 81 +-- qml/ImageSettings.qml | 58 ++ qml/ImageSettingsDialog.qml | 90 --- qml/ModeButton.qml | 38 +- qml/PipelineManager.qml | 163 +++--- qml/PostCaptureItem.qml | 93 ++-- qml/PostCapturePage.qml | 179 ------ qml/PostCaptureView.qml | 277 ++++++++++ qml/PreviewImage.qml | 49 +- qml/RecordingDurationLabel.qml | 67 +++ qml/RecordingPage.qml | 295 ---------- qml/SectionHeader.qml | 34 +- ...olsActivationData.qml => SettingsView.qml} | 20 +- qml/TextSwitch.qml | 34 +- qml/VideoOverlay.qml | 300 ++++++++++ qml/VideoPage.qml | 211 ------- qml/VideoPlayerPage.qml | 192 +++---- qml/VideoResolutionSettings.qml | 37 +- qml/VideoSettings.qml | 50 ++ qml/VideoSettingsDialog.qml | 83 --- qml/ZoomCaptureButton.qml | 77 ++- qml/ZoomCaptureCancel.qml | 63 ++- qml/ZoomSlider.qml | 117 ++-- qml/main.qml | 520 ++++++------------ qml/qml.qrc | 39 +- 33 files changed, 2388 insertions(+), 2381 deletions(-) create mode 100644 qml/CameraOverlay.qml create mode 100644 qml/CameraView.qml create mode 100644 qml/ImageOverlay.qml delete mode 100644 qml/ImagePage.qml create mode 100644 qml/ImageSettings.qml delete mode 100644 qml/ImageSettingsDialog.qml create mode 100644 qml/PostCaptureView.qml create mode 100644 qml/RecordingDurationLabel.qml delete mode 100644 qml/RecordingPage.qml rename qml/{ControlsActivationData.qml => SettingsView.qml} (71%) create mode 100644 qml/VideoOverlay.qml delete mode 100644 qml/VideoPage.qml create mode 100644 qml/VideoSettings.qml delete mode 100644 qml/VideoSettingsDialog.qml diff --git a/qml/CameraOverlay.qml b/qml/CameraOverlay.qml new file mode 100644 index 0000000..88b0849 --- /dev/null +++ b/qml/CameraOverlay.qml @@ -0,0 +1,75 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import com.nokia.meego 1.1 +import QtCamera 1.0 +import CameraPlus 1.0 + +Item { + anchors.fill: parent + id: page + + property int policyMode: CameraResources.None + + property Camera cam: null + property Item dimmer: null + property ControlsActivationData activationData: ControlsActivationData {} + property bool controlsVisible: cam.running && !standby.visible + property bool focusReticleVisible: true + property bool enableViewfinder: true + + property alias previewAnimationRunning: preview.animationRunning + + signal batteryLow + + function cameraError() { + // Nothing + } + + function policyLost() { + // Nothing + } + + onStatusChanged: { +// TODO: + if (status == PageStatus.Activating && enableViewfinder) { + cam.renderingEnabled = true + } + else if (status == PageStatus.Active) { + focusReticle.resetReticle() + + if (!enableViewfinder) { + cam.renderingEnabled = false + } + } + } + + ModeButton { + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.bottomMargin: 20 + visible: controlsVisible && activationData.modeSelectorVisible + } + +} diff --git a/qml/CameraSettings.qml b/qml/CameraSettings.qml index 2cf55d8..e2bf74d 100644 --- a/qml/CameraSettings.qml +++ b/qml/CameraSettings.qml @@ -24,75 +24,75 @@ import QtQuick 1.1 import com.nokia.meego 1.1 Column { - id: col - spacing: 10 + id: col + spacing: 10 + width: parent.width + + Label { + font.pixelSize: 36 + text: qsTr("Camera settings") width: parent.width + } + + TextSwitch { + text: qsTr("Show grid lines") + + // We have to do it that way because QML complains about a binding + // loop for checked if we bind the checked property to the settings value. + Component.onCompleted: checked = settings.gridEnabled + + onCheckedChanged: settings.gridEnabled = checked + } - Label { - font.pixelSize: 36 - text: qsTr("Camera settings"); - width: parent.width - } - - TextSwitch { - text: qsTr("Show grid lines"); - - // We have to do it that way because QML complains about a binding - // loop for checked if we bind the checked property to the settings value. - Component.onCompleted: checked = settings.gridEnabled; - - onCheckedChanged: settings.gridEnabled = checked; - } - - SectionHeader { - text: qsTr("Creator name"); - width: parent.width - } - - TextField { - placeholderText: qsTr("Name or copyright"); - width: parent.width - text: settings.creatorName - onTextChanged: settings.creatorName = text; - } - - TextSwitch { - text: qsTr("Use zoom keys for capture"); - - // We have to do it that way because QML complains about a binding - // loop for checked if we bind the checked property to the settings value. - Component.onCompleted: checked = settings.zoomAsShutter; - onCheckedChanged: settings.zoomAsShutter = checked; - } - - TextSwitch { - text: qsTr("Enable camera sounds"); - - // We have to do it that way because QML complains about a binding - // loop for checked if we bind the checked property to the settings value. - Component.onCompleted: checked = settings.soundEnabled; - onCheckedChanged: settings.soundEnabled = checked; - } - - TextSwitch { - id: useGps - text: qsTr("Use GPS"); - - // We have to do it that way because QML complains about a binding - // loop for checked if we bind the checked property to the settings value. - Component.onCompleted: checked = settings.useGps; - onCheckedChanged: settings.useGps = checked; - } - - TextSwitch { - // TODO: transition when hiding/showing and we should scroll a bit to show it - visible: useGps.checked - - text: qsTr("Use geotags"); - - // We have to do it that way because QML complains about a binding - // loop for checked if we bind the checked property to the settings value. - Component.onCompleted: checked = settings.useGeotags; - onCheckedChanged: settings.useGeotags = checked; - } + SectionHeader { + text: qsTr("Creator name") + width: parent.width + } + + TextField { + placeholderText: qsTr("Name or copyright") + width: parent.width + text: settings.creatorName + onTextChanged: settings.creatorName = text + } + + TextSwitch { + text: qsTr("Use zoom keys for capture") + + // We have to do it that way because QML complains about a binding + // loop for checked if we bind the checked property to the settings value. + Component.onCompleted: checked = settings.zoomAsShutter + onCheckedChanged: settings.zoomAsShutter = checked + } + + TextSwitch { + text: qsTr("Enable camera sounds") + + // We have to do it that way because QML complains about a binding + // loop for checked if we bind the checked property to the settings value. + Component.onCompleted: checked = settings.soundEnabled + onCheckedChanged: settings.soundEnabled = checked + } + + TextSwitch { + id: useGps + text: qsTr("Use GPS") + + // We have to do it that way because QML complains about a binding + // loop for checked if we bind the checked property to the settings value. + Component.onCompleted: checked = settings.useGps + onCheckedChanged: settings.useGps = checked + } + + TextSwitch { + // TODO: transition when hiding/showing and we should scroll a bit to show it + visible: useGps.checked + + text: qsTr("Use geotags") + + // We have to do it that way because QML complains about a binding + // loop for checked if we bind the checked property to the settings value. + Component.onCompleted: checked = settings.useGeotags + onCheckedChanged: settings.useGeotags = checked + } } diff --git a/qml/CameraToolBar.qml b/qml/CameraToolBar.qml index a797988..7bd030e 100644 --- a/qml/CameraToolBar.qml +++ b/qml/CameraToolBar.qml @@ -25,105 +25,102 @@ import com.nokia.meego 1.1 import "CameraToolBar.js" as Layout Rectangle { - id: tools - property bool expanded: false - property list items - property int targetWidth: parent.width - (2 * anchors.leftMargin) - property alias menuWidth: menu.width - property bool manualBack: false - signal clicked + id: tools + property bool expanded: false + property list items + property int targetWidth: parent.width - (2 * anchors.leftMargin) + property alias menuWidth: menu.width + property bool manualBack: false + signal clicked - height: menu.height - width: expanded ? targetWidth : menu.width - color: expanded ? "black" : width == menu.width ? "transparent" : "black" - border.color: expanded ? "gray" : width == menu.width ? "transparent" : "gray" - radius: 20 + height: menu.height + width: expanded ? targetWidth : menu.width + color: expanded ? "black" : width == menu.width ? "transparent" : "black" + border.color: expanded ? "gray" : width == menu.width ? "transparent" : "gray" + radius: 20 - Behavior on width { - PropertyAnimation { duration: 100; } - } - - ToolIcon { - property bool __isMenu: true - id: menu - anchors.verticalCenter: parent.verticalCenter - iconSource: "image://theme/icon-m-toolbar-back-white" - onClicked: { - if (tools.manualBack) { - tools.clicked(); - return; - } + Behavior on width { + PropertyAnimation { duration: 100 } + } - if (!expanded) { - expanded = true; - } - else if (Layout.stack.length == 1) { - expanded = false; - } - else { - Layout.pop(); - } - } + ToolIcon { + property bool __isMenu: true + id: menu + anchors.verticalCenter: parent.verticalCenter + iconSource: "image://theme/icon-m-toolbar-back-white" + onClicked: { + if (tools.manualBack) { + tools.clicked() + return + } - anchors.left: parent.left - rotation: 180 + if (!expanded) { + expanded = true + } else if (Layout.stack.length == 1) { + expanded = false + } else { + Layout.pop() + } } - onExpandedChanged: { - if (tools.expanded) { - tools.push(tools.items); - } - else { - tools.pop(); - } + anchors.left: parent.left + rotation: 180 + } + + onExpandedChanged: { + if (tools.expanded) { + tools.push(tools.items) + } else { + tools.pop() } + } - onWidthChanged: Layout.layout(); - onTargetWidthChanged: Layout.layout(); + onWidthChanged: Layout.layout() + onTargetWidthChanged: Layout.layout() - function push(items) { - return Layout.push(items); - } + function push(items) { + return Layout.push(items) + } - function pop() { - return Layout.pop(); - } + function pop() { + return Layout.pop() + } - state: "collapsed" - states: [ + state: "collapsed" + states: [ State { - name: "expanded" - when: tools.expanded + name: "expanded" + when: tools.expanded }, State { - name: "collapsed" - when: !tools.expanded + name: "collapsed" + when: !tools.expanded } - ] + ] - transitions: [ + transitions: [ Transition { - from: "expanded" - to: "collapsed" + from: "expanded" + to: "collapsed" - PropertyAnimation { - property: "rotation" - target: menu - from: 0 - to: 180 - duration: 500 - } + PropertyAnimation { + property: "rotation" + target: menu + from: 0 + to: 180 + duration: 500 + } }, Transition { - from: "collapsed" - to: "expanded" - PropertyAnimation { - property: "rotation" - target: menu - from: 180 - to: 360 - duration: 500 - } + from: "collapsed" + to: "expanded" + PropertyAnimation { + property: "rotation" + target: menu + from: 180 + to: 360 + duration: 500 + } } - ] + ] } diff --git a/qml/CameraView.qml b/qml/CameraView.qml new file mode 100644 index 0000000..13b2ec4 --- /dev/null +++ b/qml/CameraView.qml @@ -0,0 +1,266 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import QtCamera 1.0 +import CameraPlus 1.0 + +Camera { + id: cam + + property bool pressed: loader.item ? loader.item.pressed : false + property int policyMode: loader.item ? loader.item.policyMode : CameraResources.None + + renderingEnabled: mainView.currentItem == cam + + function policyLost() { + if (loader.item) { + loader.item.policyLost() + } + } + + function checkBattery() { + // We are fine if we are connected to the charger: + if (batteryMonitor.charging) { + return true + } + + // If we have enough battery then we are fine: + if (!batteryMonitor.critical) { + return true + } + + return false + } + + Component.onDestruction: cam.stop() + + onRunningChanged: { + if (!cam.running) { + mountProtector.unlock() + } + } + + notifications: Sounds { + id: sounds + mute: !settings.soundEnabled + } + + BatteryInfo { + id: batteryMonitor + active: cam.running + + function check() { + if (!checkBattery()) { + loader.item.batteryLow() + } + } + + onChargingChanged: { + batteryMonitor.check() + } + + onCriticalChanged: { + batteryMonitor.check() + } + } + + PreviewImage { + id: preview + } + + Connections { + target: loader.item + onPreviewAvailable: preview.setPreview(uri) + } + + Binding { + target: loader.item + property: "cam" + value: cam + when: loader.item != null + } + + Binding { + target: loader.item + property: "animationRunning" + value: preview.animationRunning + when: loader.item != null + } + + onRoiChanged: roi.normalize = false + + GridLines { + x: cam.renderArea.x + y: cam.renderArea.y + width: cam.renderArea.width + height: cam.renderArea.height + visible: settings.gridEnabled + } + + FocusReticle { + id: focusReticle + cam: cam + visible: loader.item != null && loader.item.controlsVisible && + cam.autoFocus.canFocus(cam.scene.value) + cafStatus: cam ? cam.autoFocus.cafStatus : -1 + status: cam ? cam.autoFocus.status : -1 + } + + Loader { + id: loader + property string src: mode == Camera.VideoMode ? "VideoOverlay.qml" : "ImageOverlay.qml" + anchors.fill: parent + source: Qt.resolvedUrl(src) + } + + Binding { + target: cam.flash + property: "value" + when: cam.mode == Camera.ImageMode + value: settings.imageFlashMode + } + + Binding { + target: settings + property: "imageFlashMode" + when: cam.mode == Camera.ImageMode + value: cam.flash.value + } + + Binding { + target: cam.scene + property: "value" + when: cam.mode == Camera.VideoMode + value: settings.videoSceneMode + } + + Binding { + target: cam.scene + property: "value" + when: cam.mode == Camera.ImageMode + value: settings.imageSceneMode + } + + Binding { + target: cam.evComp + property: "value" + when: cam.mode == Camera.ImageMode + value: settings.imageEvComp + } + + Binding { + target: cam.evComp + property: "value" + when: cam.mode == Camera.VideoMode + value: settings.videoEvComp + } + + Binding { + target: settings + property: "imageEvComp" + when: cam.mode == Camera.ImageMode + value: cam.evComp.value + } + + Binding { + target: settings + property: "videoEvComp" + when: cam.mode == Camera.VideoMode + value: cam.evComp.value + } + + Binding { + target: cam.whiteBalance + property: "value" + when: cam.mode == Camera.ImageMode + value: settings.imageWhiteBalance + } + + Binding { + target: cam.whiteBalance + property: "value" + when: cam.mode == Camera.VideoMode + value: settings.videoWhiteBalance + } + + Binding { + target: cam.colorTone + property: "value" + when: cam.mode == Camera.ImageMode + value: settings.imageColorFilter + } + + Binding { + target: cam.colorTone + property: "value" + when: cam.mode == Camera.VideoMode + value: settings.videoColorFilter + } + + Binding { + target: cam.iso + property: "value" + when: cam.mode == Camera.ImageMode + value: settings.imageIso + } + + Binding { + target: settings + property: "imageIso" + when: cam.mode == Camera.ImageMode + value: cam.iso.value + } + + Binding { + target: cam.videoMute + property: "enabled" + value: settings.videoMuted + } + + Binding { + target: cam.roi + property: "enabled" + value: settings.faceDetectionEnabled && !focusReticle.pressed && !focusReticle.touchMode && cam.mode == Camera.ImageMode + } + + onError: { + if (pipelineManager.error) { + // Ignore any subsequent errors. + // Killing pulseaudio while recording will lead to an + // infinite supply of errors which will break the UI + // if we show a banner for each. + return + } + + pipelineManager.error = true + if (loader.item) { + loader.item.cameraError() + } + + console.log("Camera error (" + code + "): " + message + " " + debug) + showError(qsTr("Camera error. Please restart the application.")) + // We cannot stop camera here. Seems there is a race condition somewhere + // which leads to a freeze if we do so. + } + +} diff --git a/qml/CaptureButton.qml b/qml/CaptureButton.qml index 28c9402..38e1f0e 100644 --- a/qml/CaptureButton.qml +++ b/qml/CaptureButton.qml @@ -24,42 +24,41 @@ import QtQuick 1.1 import com.nokia.meego 1.1 Item { - id: button + id: button - property url iconSource - property Style platformStyle: ButtonStyle {} + property url iconSource + property Style platformStyle: ButtonStyle {} - property alias pressed: mouse.pressed - property alias containsMouse: mouse.containsMouse - property alias mouseX: mouse.mouseX - property alias mouseY: mouse.mouseY + property alias pressed: mouse.pressed + property alias mouseX: mouse.mouseX + property alias mouseY: mouse.mouseY - signal clicked - signal exited + signal clicked + signal exited - MouseArea { - id: mouse - anchors.fill: parent - onClicked: button.clicked(); - onExited: button.exited(); - } + MouseArea { + id: mouse + anchors.fill: parent + onClicked: button.clicked() + onExited: button.exited() + } - BorderImage { - id: background - anchors.fill: parent - border.left: button.platformStyle.backgroundMarginLeft - border.top: button.platformStyle.backgroundMarginTop - border.right: button.platformStyle.backgroundMarginRight - border.bottom: button.platformStyle.backgroundMarginBottom - source: pressed ? button.platformStyle.pressedBackground : button.platformStyle.background - } + BorderImage { + id: background + anchors.fill: parent + border.left: button.platformStyle.backgroundMarginLeft + border.top: button.platformStyle.backgroundMarginTop + border.right: button.platformStyle.backgroundMarginRight + border.bottom: button.platformStyle.backgroundMarginBottom + source: pressed ? button.platformStyle.pressedBackground : button.platformStyle.background + } - Image { - id: icon - anchors.centerIn: parent - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: -1 - source: button.iconSource - visible: source != "" - } + Image { + id: icon + anchors.centerIn: parent + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: -1 + source: button.iconSource + visible: source != "" + } } \ No newline at end of file diff --git a/qml/FocusReticle.qml b/qml/FocusReticle.qml index 4d1b737..dd22a7e 100644 --- a/qml/FocusReticle.qml +++ b/qml/FocusReticle.qml @@ -28,208 +28,200 @@ import CameraPlus 1.0 // TODO: hide all controls when we are dragging MouseArea { - id: mouse - x: cam ? cam.renderArea.x : 0 - y: cam ? cam.renderArea.y : 0 - width: cam ? cam.renderArea.width : 0 - height: cam ? cam.renderArea.height : 0 - drag.minimumX: 0 - drag.minimumY: 0 - drag.maximumX: width - reticle.width - drag.maximumY: height - reticle.height - - property int cafStatus: AutoFocus.None - property int status: AutoFocus.None - property Camera cam - property bool touchMode - - property variant touchPoint: Qt.point(mouse.width / 2, mouse.height / 2) - - // A 100x100 central "rectangle" - property variant centerRect: Qt.rect((mouse.width / 2 - 50), (mouse.height / 2) - 50, 100, 100); - - // ROI: - property variant primaryRoiRect: Qt.rect(0, 0, 0, 0); - property variant roiRects - property variant allRoiRects - property bool roiMode: allRoiRects != null && allRoiRects.length > 0 && !touchMode && !pressed - - onPressed: calculateTouchPoint(mouse.x, mouse.y); - onReleased: calculateTouchPoint(mouse.x, mouse.y); - onPositionChanged: calculateTouchPoint(mouse.x, mouse.y); - - function resetReticle() { - calculateTouchPoint(centerRect.x, centerRect.y) + id: mouse + x: cam ? cam.renderArea.x : 0 + y: cam ? cam.renderArea.y : 0 + width: cam ? cam.renderArea.width : 0 + height: cam ? cam.renderArea.height : 0 + drag.minimumX: 0 + drag.minimumY: 0 + drag.maximumX: width - reticle.width + drag.maximumY: height - reticle.height + + property int cafStatus: AutoFocus.None + property int status: AutoFocus.None + property Camera cam + property bool touchMode + + property variant touchPoint: Qt.point(mouse.width / 2, mouse.height / 2) + + // A 100x100 central "rectangle" + property variant centerRect: Qt.rect((mouse.width / 2 - 50), (mouse.height / 2) - 50, 100, 100) + + // ROI: + property variant primaryRoiRect: Qt.rect(0, 0, 0, 0) + property variant roiRects + property variant allRoiRects + property bool roiMode: allRoiRects != null && allRoiRects.length > 0 && !touchMode && !pressed + + onPressed: calculateTouchPoint(mouse.x, mouse.y) + onReleased: calculateTouchPoint(mouse.x, mouse.y) + onPositionChanged: calculateTouchPoint(mouse.x, mouse.y) + + function resetReticle() { + calculateTouchPoint(centerRect.x, centerRect.y) + } + + function setRegionOfInterest() { + if (!cam) { + // console.log("Cannot set ROI without camera object") + return + } else if (mouse.pressed) { + // console.log("Will not set ROI while pressed") + return + } else if (!touchMode && !roiMode) { + // console.log("resetting ROI") + cam.roi.resetRegionOfInterest() + return } - function setRegionOfInterest() { - if (!cam) { -// console.log("Cannot set ROI without camera object"); - return; - } - - if (mouse.pressed) { -// console.log("Will not set ROI while pressed"); - return; - } - - if (!touchMode && !roiMode) { -// console.log("resetting ROI"); - cam.roi.resetRegionOfInterest(); - return; - } - -// TODO: rework this and move to unnormalized coordinates - // in terms of video resolution: - var rx = (cam.videoResolution.width * reticle.x) / mouse.width; - var rwidth = (cam.videoResolution.width * reticle.width) / mouse.width; - var ry = (cam.videoResolution.height * reticle.y) / mouse.height; - var rheight = (cam.videoResolution.height * reticle.height) / mouse.height; - - // Translate to normalized coordinates (1x1 square) as expected by our C++ backend - rx = rx / cam.videoResolution.width; - rwidth = rwidth / cam.videoResolution.width; - ry = ry / cam.videoResolution.height; - rheight = rheight / cam.videoResolution.height; - -// console.log("Setting ROI to: " + rx + "x" + ry); - cam.roi.setRegionOfInterest(Qt.rect(rx, ry, rwidth, rheight)); + // TODO: rework this and move to unnormalized coordinates + // in terms of video resolution: + var rx = (cam.videoResolution.width * reticle.x) / mouse.width + var rwidth = (cam.videoResolution.width * reticle.width) / mouse.width + var ry = (cam.videoResolution.height * reticle.y) / mouse.height + var rheight = (cam.videoResolution.height * reticle.height) / mouse.height + + // Translate to normalized coordinates (1x1 square) as expected by our C++ backend + rx = rx / cam.videoResolution.width + rwidth = rwidth / cam.videoResolution.width + ry = ry / cam.videoResolution.height + rheight = rheight / cam.videoResolution.height + + // console.log("Setting ROI to: " + rx + "x" + ry) + cam.roi.setRegionOfInterest(Qt.rect(rx, ry, rwidth, rheight)) + } + + function calculateTouchPoint(x, y) { + if (x >= centerRect.x && y >= centerRect.y && + x <= centerRect.x + centerRect.width && + y <= centerRect.y + centerRect.height) { + touchMode = false + touchPoint = Qt.point(mouse.width / 2, mouse.height / 2) + return } - function calculateTouchPoint(x, y) { - if (x >= centerRect.x && y >= centerRect.y && - x <= centerRect.x + centerRect.width && - y <= centerRect.y + centerRect.height) { - touchMode = false; - touchPoint = Qt.point(mouse.width / 2, mouse.height / 2) - return; - } - - touchMode = true; - touchPoint = Qt.point(x, y) + touchMode = true + touchPoint = Qt.point(x, y) + } + + function predictColor(caf, status) { + if (status == AutoFocus.Success) { + return "steelblue" + } else if (status == AutoFocus.Fail) { + return "red" + } else if (status == AutoFocus.Running) { + return "white" + } else if (caf == AutoFocus.Success) { + return "steelblue" + } else { + return "white" } - - function predictColor(caf, status) { - if (status == AutoFocus.Success) { - return "steelblue"; - } - else if (status == AutoFocus.Fail) { - return "red"; - } - else if (status == AutoFocus.Running) { - return "white"; - } - else if (caf == AutoFocus.Success) { - return "steelblue"; - } - else { - return "white"; - } + } + + Repeater { + anchors.fill: parent + model: roiMode ? roiRects : 0 + + delegate: Rectangle { + x: modelData.x + y: modelData.y + width: modelData.width + height: modelData.height + color: "transparent" + border.color: "gray" + border.width: 2 } - - Repeater { - anchors.fill: parent - model: roiMode ? roiRects : 0 - - delegate: Rectangle { - x: modelData.x - y: modelData.y - width: modelData.width - height: modelData.height - color: "transparent" - border.color: "gray" - border.width: 2 - } + } + + FocusRectangle { + id: reticle + width: mouse.pressed ? 150 : mouse.touchMode ? 200 : roiMode ? primaryRoiRect.width : 250 + height: mouse.pressed ? 90 : mouse.touchMode ? 120 : roiMode ? primaryRoiRect.height : 150 + x: Math.min(Math.max(mouse.touchPoint.x - (width / 2), drag.minimumX), drag.maximumX) + y: Math.min(Math.max(mouse.touchPoint.y - (height / 2), drag.minimumY), drag.maximumY) + color: predictColor(cafStatus, status) + + onXChanged: setRegionOfInterest() + onYChanged: setRegionOfInterest() + /* + Behavior on x { + PropertyAnimation { duration: 100 } + enabled: !mouse.pressed } - FocusRectangle { - id: reticle - width: mouse.pressed ? 150 : mouse.touchMode ? 200 : roiMode ? primaryRoiRect.width : 250 - height: mouse.pressed ? 90 : mouse.touchMode ? 120 : roiMode ? primaryRoiRect.height : 150 - x: Math.min(Math.max(mouse.touchPoint.x - (width / 2), drag.minimumX), drag.maximumX); - y: Math.min(Math.max(mouse.touchPoint.y - (height / 2), drag.minimumY), drag.maximumY); - - color: predictColor(cafStatus, status); - - onXChanged: setRegionOfInterest(); - onYChanged: setRegionOfInterest(); -/* - Behavior on x { - PropertyAnimation { duration: 100; } - enabled: !mouse.pressed - } - - Behavior on y { - PropertyAnimation { duration: 100; } - enabled: !mouse.pressed - } -*/ - Behavior on width { - PropertyAnimation { duration: 100; } - } - - Behavior on height { - PropertyAnimation { duration: 100; } - } - + Behavior on y { + PropertyAnimation { duration: 100 } + enabled: !mouse.pressed } - - Connections { - target: settings - // Changing mode (which implies changing pages) will not reset ROI - // thus we do it here - onModeChanged: resetReticle(); + */ + Behavior on width { + PropertyAnimation { duration: 100 } } - Connections { - target: cam - onRunningChanged: resetReticle() - onVideoResolutionChanged: resetReticle() - } - - Connections { - target: cam.roi - onRegionsChanged: { - allRoiRects = regions; - primaryRoiRect = primary; - roiRects = rest; - - if (regions.length == 0) { - resetReticle(); - return; - } - - touchPoint = Qt.point(primary.x + (reticle.width / 2), - primary.y + (reticle.height / 2)); - } - } -/* - // This is for debugging - Rectangle { - color: "blue" - opacity: 0.2 - anchors.fill: parent + Behavior on height { + PropertyAnimation { duration: 100 } } - Rectangle { - color: "red" - opacity: 0.4 - x: centerRect.x - y: centerRect.y - width: centerRect.width - height: centerRect.height + } + + Connections { + target: settings + // Changing mode (which implies changing pages) will not reset ROI + // thus we do it here + onModeChanged: resetReticle() + } + + Connections { + target: cam + onRunningChanged: resetReticle() + onVideoResolutionChanged: resetReticle() + } + + Connections { + target: cam.roi + onRegionsChanged: { + allRoiRects = regions + primaryRoiRect = primary + roiRects = rest + + if (regions.length == 0) { + resetReticle() + return + } + + touchPoint = Qt.point(primary.x + (reticle.width / 2), + primary.y + (reticle.height / 2)) } -*/ - Timer { - interval: 500 - running: status == AutoFocus.Running - triggeredOnStart: true - repeat: true - onTriggered: reticle.visible = !reticle.visible - onRunningChanged: { - if (!running) { - reticle.visible = true; - } - } + } + + /* + // This is for debugging + Rectangle { + color: "blue" + opacity: 0.2 + anchors.fill: parent + } + + Rectangle { + color: "red" + opacity: 0.4 + x: centerRect.x + y: centerRect.y + width: centerRect.width + height: centerRect.height + } + */ + Timer { + interval: 500 + running: status == AutoFocus.Running + triggeredOnStart: true + repeat: true + onTriggered: reticle.visible = !reticle.visible + onRunningChanged: { + if (!running) { + reticle.visible = true + } } + } } diff --git a/qml/ImageOverlay.qml b/qml/ImageOverlay.qml new file mode 100644 index 0000000..842768d --- /dev/null +++ b/qml/ImageOverlay.qml @@ -0,0 +1,255 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import com.nokia.meego 1.1 +import QtCamera 1.0 +import CameraPlus 1.0 +import "data.js" as Data + +Item { + id: overlay + + property Camera cam + property bool animationRunning: false + property int policyMode: CameraResources.Image + property bool pressed: capture.pressed || zoomSlider.pressed || modeButton.pressed + property bool controlsVisible: imageMode.canCapture && cam.running && !animationRunning + && dimmer.opacity == 0.0 && !cameraMode.busy + + signal previewAvailable(string uri) + + anchors.fill: parent + + ImageMode { + id: imageMode + camera: cam + onPreviewAvailable: { + overlay.previewAvailable(preview) + cam.autoFocus.stopAutoFocus() + } + + onSaved: mountProtector.unlock() + } + + ZoomSlider { + id: zoomSlider + camera: cam + anchors.top: parent.top + anchors.topMargin: 0 + anchors.horizontalCenter: parent.horizontalCenter + visible: controlsVisible + } + + ModeButton { + id: modeButton + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.bottomMargin: 20 + visible: controlsVisible + } + + CaptureButton { + id: capture + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.verticalCenter: parent.verticalCenter + iconSource: "image://theme/icon-m-camera-shutter" + width: 75 + height: 75 + opacity: 0.5 + onClicked: captureImage() + visible: controlsVisible && (!settings.zoomAsShutter && keys.active) + + onExited: { + if (mouseX <= 0 || mouseY <= 0 || mouseX > width || mouseY > height) { + // Release outside the button: + cam.autoFocus.stopAutoFocus() + } + } + } + + Timer { + id: autoFocusTimer + interval: 200 + running: capture.pressed || zoomCapture.zoomPressed + repeat: false + onTriggered: { + if (cam.autoFocus.cafStatus != AutoFocus.Success) { + cam.autoFocus.startAutoFocus() + } + } + } + + ZoomCaptureButton { + id: zoomCapture + onReleased: parent.captureImage() + } + + ZoomCaptureCancel { + anchors.fill: parent + zoomCapture: zoomCapture + onCanceled: { + if (!autoFocusTimer.running) { + cam.autoFocus.stopAutoFocus() + } + } + } + + CameraToolBar { + id: toolBar + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + opacity: 0.5 + targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5) + visible: controlsVisible + expanded: settings.showToolBar + onExpandedChanged: settings.showToolBar = expanded + items: [ + FlashButton { + onClicked: toolBar.push(items) + }, + ImageSceneButton { + onClicked: toolBar.push(items) + }, + ImageEvCompButton { + onClicked: toolBar.push(items) + }, + ImageWhiteBalanceButton { + onClicked: toolBar.push(items) + }, + ImageColorFilterButton { + onClicked: toolBar.push(items) + }, + ImageIsoButton { + onClicked: toolBar.push(items) + } + ] + } + + Rectangle { + id: indicators + anchors.top: parent.top + anchors.topMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + width: 48 + height: col.height + color: "black" + border.color: "gray" + radius: 20 + opacity: 0.5 + visible: controlsVisible + + Column { + id: col + width: parent.width + spacing: 5 + + Indicator { + id: resolutionIndicator + source: "image://theme/" + Data.imageIcon(settings.imageAspectRatio, settings.imageResolution) + } + + Indicator { + id: wbIndicator + source: visible ? "image://theme/" + Data.wbIcon(settings.imageWhiteBalance) + "-screen" : "" + visible: settings.imageWhiteBalance != WhiteBalance.Auto + } + + Indicator { + id: cfIndicator + source: "image://theme/" + Data.cfIcon(settings.imageColorFilter) + "-screen" + visible: settings.imageColorFilter != ColorTone.Normal + } + + Indicator { + id: isoIndicator + visible: settings.imageIso != 0 + source: "image://theme/" + Data.isoIcon(settings.imageIso) + } + + Indicator { + id: gpsIndicator + visible: settings.useGps + source: "image://theme/icon-m-camera-location" + + PropertyAnimation on opacity { + easing.type: Easing.OutSine + loops: Animation.Infinite + from: 0.2 + to: 1.0 + duration: 1000 + running: settings.useGps && !positionSource.position.longitudeValid + alwaysRunToEnd: true + } + } + + Indicator { + id: faceDetectionIndicator + visible: settings.faceDetectionEnabled + source: "image://theme/icon-m-camera-face-detection-screen" + } + + } + } + + function cameraError() { + mountProtector.unlock() + } + + function policyLost() { + // Nothing + } + + function batteryLow() { + // Nothing + } + + function captureImage() { + if (!imageMode.canCapture) { + showError(qsTr("Camera is already capturing an image.")) + } else if (!checkBattery()) { + showError(qsTr("Not enough battery to capture images.")) + } else if (!fileSystem.available) { + showError(qsTr("Camera cannot capture images in mass storage mode.")) + } else if (!checkDiskSpace()) { + showError(qsTr("Not enough space to capture images.")) + } else if (!mountProtector.lock()) { + showError(qsTr("Failed to lock images directory.")) + } else { + metaData.setMetaData() + + var fileName = fileNaming.imageFileName() + if (!imageMode.capture(fileName)) { + showError(qsTr("Failed to capture image. Please restart the camera.")) + mountProtector.unlock() + } else { + trackerStore.storeImage(fileName) + } + } + } + +} diff --git a/qml/ImagePage.qml b/qml/ImagePage.qml deleted file mode 100644 index 65950de..0000000 --- a/qml/ImagePage.qml +++ /dev/null @@ -1,278 +0,0 @@ -// -*- qml -*- - -/*! - * This file is part of CameraPlus. - * - * Copyright (C) 2012-2013 Mohammed Sameer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -import QtQuick 1.1 -import com.nokia.meego 1.1 -import QtCamera 1.0 -import CameraPlus 1.0 -import "data.js" as Data - -CameraPage { - id: page - - policyMode: CameraResources.Image - controlsVisible: imageMode.canCapture && !cameraMode.busy && dimmer.opacity == 0.0 && !previewAnimationRunning && cam.running - - orientationLock: PageOrientation.LockLandscape - - property Item settingsDialog: null - - function cameraError() { - mountProtector.unlock(); - } - - function captureImage() { - if (!imageMode.canCapture) { - showError(qsTr("Camera is already capturing an image.")); - return; - } - - if (!checkBattery()) { - showError(qsTr("Not enough battery to capture images.")); - return; - } - - if (!fileSystem.available) { - showError(qsTr("Camera cannot capture images in mass storage mode.")); - return; - } - - if (!checkDiskSpace()) { - showError(qsTr("Not enough space to capture images.")); - return; - } - - if (!mountProtector.lock()) { - showError(qsTr("Failed to lock images directory.")); - return; - } - - metaData.setMetaData(); - - var fileName = fileNaming.imageFileName(); - if (!imageMode.capture(fileName)) { - showError(qsTr("Failed to capture image. Please restart the camera.")); - return; - } - - trackerStore.storeImage(fileName); - } - - CaptureButton { - id: capture - anchors.right: parent.right - anchors.rightMargin: 20 - anchors.verticalCenter: parent.verticalCenter - iconSource: "image://theme/icon-m-camera-shutter" - width: 75 - height: 75 - opacity: 0.5 - onClicked: captureImage(); - visible: controlsVisible && (!settings.zoomAsShutter && keys.active) - - onExited: { - if (mouseX <= 0 || mouseY <= 0 || mouseX > width || mouseY > height) { - // Release outside the button: - cam.autoFocus.stopAutoFocus(); - } - } - } - - ZoomCaptureButton { - id: zoomCapture - page: page - onReleased: page.captureImage(); - } - - ZoomCaptureCancel { - anchors.fill: parent - page: page - zoomCapture: zoomCapture - onCanceled: { - if (!autoFocusTimer.running) { - cam.autoFocus.stopAutoFocus(); - } - } - } - - Timer { - id: autoFocusTimer - interval: 200 - running: capture.pressed || zoomCapture.zoomPressed - repeat: false - onTriggered: { - if (cam.autoFocus.cafStatus != AutoFocus.Success) { - cam.autoFocus.startAutoFocus(); - } - } - } - - ImageMode { - id: imageMode - camera: cam - onPreviewAvailable: { - page.setPreview(preview); - cam.autoFocus.stopAutoFocus(); - } - - onSaved: mountProtector.unlock(); - } - - Rectangle { - id: indicators - anchors.top: parent.top - anchors.topMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - width: 48 - height: col.height - color: "black" - border.color: "gray" - radius: 20 - opacity: 0.5 - visible: controlsVisible - - Column { - id: col - width: parent.width - spacing: 5 - - Indicator { - id: resolutionIndicator - source: "image://theme/" + Data.imageIcon(settings.imageAspectRatio, settings.imageResolution); - } - - Indicator { - id: wbIndicator - source: visible ? "image://theme/" + Data.wbIcon(settings.imageWhiteBalance) + "-screen" : "" - visible: settings.imageWhiteBalance != WhiteBalance.Auto - } - - Indicator { - id: cfIndicator - source: "image://theme/" + Data.cfIcon(settings.imageColorFilter) + "-screen" - visible: settings.imageColorFilter != ColorTone.Normal - } - - Indicator { - id: isoIndicator - visible: settings.imageIso != 0 - source: "image://theme/" + Data.isoIcon(settings.imageIso); - } - - Indicator { - id: gpsIndicator - visible: settings.useGps - source: "image://theme/icon-m-camera-location" - - PropertyAnimation on opacity { - easing.type: Easing.OutSine - loops: Animation.Infinite - from: 0.2 - to: 1.0 - duration: 1000 - running: settings.useGps && !positionSource.position.longitudeValid - alwaysRunToEnd: true - } - } - - Indicator { - id: faceDetectionIndicator - visible: settings.faceDetectionEnabled - source: "image://theme/icon-m-camera-face-detection-screen" - } - - } - } - - Button { - id: cameraRoll - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: 20 - anchors.rightMargin: 20 - width: 56 - height: 56 - - opacity: 0.5 - iconSource: "image://theme/icon-m-camera-roll" - onClicked: openFile("PostCapturePage.qml"); - visible: controlsVisible - } - - CameraToolBar { - id: toolBar - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - opacity: 0.5 - targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5) - visible: controlsVisible - expanded: settings.showToolBar - onExpandedChanged: settings.showToolBar = expanded; - - items: [ - FlashButton { - onClicked: toolBar.push(items); - }, - ImageSceneButton { - onClicked: toolBar.push(items); - }, - ImageEvCompButton { - onClicked: toolBar.push(items); - }, - ImageWhiteBalanceButton { - onClicked: toolBar.push(items); - }, - ImageColorFilterButton { - onClicked: toolBar.push(items); - }, - ImageIsoButton { - onClicked: toolBar.push(items); - }, - ToolIcon { - iconSource: "image://theme/icon-m-toolbar-view-menu-white" - onClicked: openSettings(); - } - ] - } - - function openSettings() { - var roiEnabled = cam.roi.enabled; - cam.roi.enabled = false; - - if (!settingsDialog) { - settingsDialog = imageSettingsDialog.createObject(page); - } - - settingsDialog.open(); - - cam.roi.enabled = roiEnabled; - } - - Component { - id: imageSettingsDialog - - ImageSettingsDialog { } - } -} diff --git a/qml/ImageResolutionSettings.qml b/qml/ImageResolutionSettings.qml index b57570e..bfd1309 100644 --- a/qml/ImageResolutionSettings.qml +++ b/qml/ImageResolutionSettings.qml @@ -24,54 +24,55 @@ import QtQuick 1.1 import com.nokia.meego 1.1 Column { - spacing: 10 + spacing: 10 - SectionHeader { - text: qsTr("Aspect ratio"); - } + SectionHeader { + text: qsTr("Aspect ratio") + } - ButtonRow { - id: aspectRatioRow - width: parent.width - enabled: cam.idle - exclusive: false + ButtonRow { + id: aspectRatioRow + width: parent.width + enabled: cam.idle + exclusive: false - Repeater { - model: imageSettings.aspectRatios - delegate: Button { - text: qsTr(modelData); - checked: settings.imageAspectRatio == modelData; - onClicked: settings.imageAspectRatio = modelData; - } - } + Repeater { + model: imageSettings.aspectRatios + delegate: Button { + text: qsTr(modelData) + checked: settings.imageAspectRatio == modelData + onClicked: settings.imageAspectRatio = modelData + } } + } - SectionHeader { - text: qsTr("Resolution"); - } + SectionHeader { + text: qsTr("Resolution") + } - ButtonRow { - id: resolutionsRow - width: parent.width - enabled: cam.idle - exclusive: false + ButtonRow { + id: resolutionsRow + width: parent.width + enabled: cam.idle + exclusive: false - Binding { - target: imageSettings.resolutions - property: "aspectRatio" - value: settings.imageAspectRatio - } + Binding { + target: imageSettings.resolutions + property: "aspectRatio" + value: settings.imageAspectRatio + } - Repeater { - id: resolutions - model: imageSettings.resolutions.aspectRatio == settings.imageAspectRatio ? imageSettings.resolutions : undefined + Repeater { + id: resolutions + model: imageSettings.resolutions.aspectRatio == settings.imageAspectRatio ? + imageSettings.resolutions : undefined - delegate: Button { - font.capitalization: Font.Capitalize - text: qsTr("%1 %2 Mpx").arg(resolutionName).arg(megaPixels); - checked: settings.imageResolution == resolutionName - onClicked: settings.imageResolution = resolutionName; - } - } + delegate: Button { + font.capitalization: Font.Capitalize + text: qsTr("%1 %2 Mpx").arg(resolutionName).arg(megaPixels) + checked: settings.imageResolution == resolutionName + onClicked: settings.imageResolution = resolutionName + } } + } } diff --git a/qml/ImageSettings.qml b/qml/ImageSettings.qml new file mode 100644 index 0000000..bfd862a --- /dev/null +++ b/qml/ImageSettings.qml @@ -0,0 +1,58 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import com.nokia.meego 1.1 +import QtCamera 1.0 + +Flickable { + contentHeight: col.height + anchors.fill: parent + anchors.margins: 10 + + Column { + id: col + width: parent.width + spacing: 10 + + Label { + font.pixelSize: 36 + text: qsTr("Image settings") + } + + ImageResolutionSettings { + width: parent.width + } + + TextSwitch { + text: qsTr("Enable face detection") + // We have to do it that way because QML complains about a binding + // loop for checked if we bind the checked property to the settings value. + Component.onCompleted: checked = settings.faceDetectionEnabled + onCheckedChanged: settings.faceDetectionEnabled = checked + } + + CameraSettings { + anchors.horizontalCenter: parent.horizontalCenter + } + } +} diff --git a/qml/ImageSettingsDialog.qml b/qml/ImageSettingsDialog.qml deleted file mode 100644 index 0111dd9..0000000 --- a/qml/ImageSettingsDialog.qml +++ /dev/null @@ -1,90 +0,0 @@ -// -*- qml -*- - -/*! - * This file is part of CameraPlus. - * - * Copyright (C) 2012-2013 Mohammed Sameer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -import QtQuick 1.1 -import com.nokia.meego 1.1 -import QtCamera 1.0 - -Dialog { - id: dialog - - content: item - - Connections { - target: Qt.application - onActiveChanged: { - if (!Qt.application.active) { - dialog.close(); - } - } - } - - onStatusChanged: { - if (status == DialogStatus.Open) { - cam.renderingEnabled = false; - } - else if (status == DialogStatus.Closing) { - cam.renderingEnabled = true; - } - } - - Item { - id: item - width: parent.width - height: root.height - - Flickable { - id: flickable - anchors.fill: parent - anchors.margins: 10 - contentHeight: col.height - - Column { - id: col - - width: parent.width - spacing: 10 - - Label { - font.pixelSize: 36 - text: qsTr("Image settings"); - } - - ImageResolutionSettings { - width: parent.width - } - - TextSwitch { - text: qsTr("Enable face detection"); - // We have to do it that way because QML complains about a binding - // loop for checked if we bind the checked property to the settings value. - Component.onCompleted: checked = settings.faceDetectionEnabled; - onCheckedChanged: settings.faceDetectionEnabled = checked; - } - - CameraSettings { - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } -} diff --git a/qml/ModeButton.qml b/qml/ModeButton.qml index d1ef4e0..31a19cf 100644 --- a/qml/ModeButton.qml +++ b/qml/ModeButton.qml @@ -23,33 +23,21 @@ import QtQuick 1.1 import QtCamera 1.0 -import com.nokia.meego 1.0 -Item { - width: selector.width * selector.scale - height: selector.height * selector.scale +CaptureButton { + width: 55 + height: 55 + opacity: 0.5 - Switch { - id: selector - scale: 1.5 - anchors.centerIn: parent - checked: settings.mode == Camera.ImageMode - - onCheckedChanged: { - if (checked) { - settings.mode = Camera.ImageMode; - } - else { - settings.mode = Camera.VideoMode; - } - } - - platformStyle: SwitchStyle { - thumbPressed: settings.mode == Camera.VideoMode ? "image://theme/icon-m-camera-video" : "image://theme/icon-m-viewfinder-camera" - switchOn: "" - switchOff: "" - thumb: settings.mode == Camera.VideoMode ? "image://theme/icon-m-viewfinder-camera" : "image://theme/icon-m-camera-video" - } + iconSource: settings.mode == Camera.VideoMode ? + "image://theme/icon-m-viewfinder-camera" : + "image://theme/icon-m-camera-video" + onClicked: { + if (settings.mode == Camera.VideoMode) { + settings.mode = Camera.ImageMode + } else { + settings.mode = Camera.VideoMode } + } } diff --git a/qml/PipelineManager.qml b/qml/PipelineManager.qml index e5b87ac..cd33a48 100644 --- a/qml/PipelineManager.qml +++ b/qml/PipelineManager.qml @@ -25,116 +25,119 @@ import QtCamera 1.0 import CameraPlus 1.0 Item { - id: handler + id: handler - property bool showStandBy: state != "on" + property bool showStandBy: state != "on" - property alias acquired: policy.acquired - property alias hijacked: policy.hijacked - property alias scaleAcquired: policy.scaleAcquired + property alias acquired: policy.acquired + property alias hijacked: policy.hijacked + property alias scaleAcquired: policy.scaleAcquired - property Camera camera: null - property Item currentPage: pageStack.currentPage - property bool error: false + property Camera camera: null + property Item currentItem + property bool error: false - onCurrentPageChanged: { - if (state == "on" || state == "policyLost") { - startCamera(); - } + onCurrentItemChanged: { + if (state == "on" || state == "policyLost") { + startCamera() } - - CameraResources { - id: policy + } + + Connections { + target: currentItem + onPolicyModeChanged: { + if (state == "on" || state == "policyLost") { + startCamera() + } } - - function startCamera() { - if (error) { - return; - } - - if (!policy.acquire(currentPage.policyMode)) { - console.log("Failed to acquire policy resources"); - return; - } - - if (!camera.start()) { - showError(qsTr("Failed to start camera. Please restart the application.")); - } + } + + CameraResources { + id: policy + } + + function startCamera() { + if (error) { + return + } else if (!policy.acquire(currentItem.policyMode)) { + console.log("Failed to acquire policy resources") + return + } else if (!camera.start()) { + showError(qsTr("Failed to start camera. Please restart the application.")) } + } - function stopCamera() { - if (camera.stop(false)) { - policy.acquire(CameraResources.None); - error = false; - } + function stopCamera() { + if (camera.stop(false)) { + policy.acquire(CameraResources.None) + error = false } + } - function forceStopCamera() { - // We don't release resources here so we can get them back - // when they become available - pageStack.currentPage.policyLost(); - camera.stop(true); - error = false; - } + function forceStopCamera() { + // We don't release resources here so we can get them back + // when they become available + currentItem.policyLost() + camera.stop(true) + error = false + } - state: "off" + state: "off" -// onStateChanged: console.log("New state " + handler.state); +// onStateChanged: console.log("New state " + handler.state); - states: [ + states: [ State { - name: "on" - when: Qt.application.active && currentPage && currentPage.policyMode != CameraResources.None && !policy.hijacked + name: "on" + when: Qt.application.active && currentItem && currentItem.policyMode != CameraResources.None && !policy.hijacked }, State { - name: "off" - when: (!Qt.application.active && camera.idle) || (currentPage && currentPage.policyMode == CameraResources.None && camera.idle) + name: "off" + when: (!Qt.application.active && camera.idle) || (currentItem && currentItem.policyMode == CameraResources.None && camera.idle) }, State { - name: "policyLost" - when: policy.hijacked + name: "policyLost" + when: policy.hijacked }, State { - name: "error" + name: "error" } - ] + ] - transitions: [ + transitions: [ Transition { - to: "off" - ScriptAction { - script: stopCamera(); - } + to: "off" + ScriptAction { + script: stopCamera() + } }, Transition { - from: "off" - to: "on" - ScriptAction { - script: handler.startCamera(); - } + from: "off" + to: "on" + ScriptAction { + script: handler.startCamera() + } }, - Transition { - from: "on" - to: "policyLost" - ScriptAction { - script: forceStopCamera(); - } + from: "on" + to: "policyLost" + ScriptAction { + script: forceStopCamera() + } }, - Transition { - from: "policyLost" - to: "off" - ScriptAction { - script: stopCamera(); - } + from: "policyLost" + to: "off" + ScriptAction { + script: stopCamera() + } }, Transition { - from: "policyLost" - to: "on" - ScriptAction { - script: startCamera(); - } + from: "policyLost" + to: "on" + ScriptAction { + script: startCamera() + } } - ] + ] } diff --git a/qml/PostCaptureItem.qml b/qml/PostCaptureItem.qml index a67fb38..af18fdb 100644 --- a/qml/PostCaptureItem.qml +++ b/qml/PostCaptureItem.qml @@ -25,57 +25,60 @@ import com.nokia.meego 1.1 import CameraPlus 1.0 Item { - id: postCaptureItem - property bool isVideo: itemData.type.search("nmm#Video") > 0 - property alias error: image.error - property variant itemData: item - property bool isCurrentItem: PathView.isCurrentItem - signal clicked + id: postCaptureItem + property bool isVideo: itemData.type.search("nmm#Video") > 0 + property alias error: image.error + property variant itemData: item + property bool playing: loader.source != "" + signal clicked - onIsCurrentItemChanged: { - if (isCurrentItem) { - page.currentItem = postCaptureItem; - } - } - - function startPlayback() { - openFileNow("VideoPlayerPage.qml"); - pageStack.currentPage.source = itemData.url; - pageStack.currentPage.play(); - } + function startPlayback() { + loader.source = Qt.resolvedUrl("VideoPlayerPage.qml") + loader.item.source = itemData.url + loader.item.play() + } - Label { - anchors.fill: parent - visible: image.error && page.status == PageStatus.Active - text: qsTr("Failed to load preview"); - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - font.pixelSize: 32 - } + Loader { + id: loader + anchors.fill: parent + } - QuillItem { - id: image - width: parent.width - 10 - height: parent.height - anchors.centerIn: parent + Connections { + target: loader.item + onFinished: loader.source = "" + } - visible: page.status == PageStatus.Activating || page.status == PageStatus.Active && !error + QuillItem { + id: image + width: parent.width - 10 + height: parent.height + anchors.centerIn: parent + Component.onCompleted: initialize(itemData.url, itemData.mimetype) + visible: loader.source == "" - Component.onCompleted: initialize(itemData.url, itemData.mimetype); + Label { + anchors.fill: parent + visible: image.error + text: qsTr("Failed to load preview") + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 32 + } - MouseArea { - id: mouse - anchors.fill: parent - enabled: true - onClicked: postCaptureItem.clicked(); - } + MouseArea { + id: mouse + anchors.fill: parent + enabled: true + onClicked: postCaptureItem.clicked() + } - ToolIcon { - id: playIcon - anchors.centerIn: parent - iconSource: "image://theme/icon-s-music-video-play" - visible: isVideo - onClicked: startPlayback(); - } + ToolIcon { + // TODO: this is overlapping with error. + id: playIcon + anchors.centerIn: parent + iconSource: "image://theme/icon-s-music-video-play" + visible: isVideo + onClicked: startPlayback() } + } } diff --git a/qml/PostCapturePage.qml b/qml/PostCapturePage.qml index 4b1f13c..fb9bd56 100644 --- a/qml/PostCapturePage.qml +++ b/qml/PostCapturePage.qml @@ -37,106 +37,6 @@ CameraPage { Component.onCompleted: postCaptureModel.reload(); - function launchGallery() { - if (!gallery.launch()) { - showError(qsTr("Failed to launch gallery")); - } - } - - function showInGallery() { - if (!available) { - return; - } - - if (!gallery.show(currentItem.itemUrl)) { - showError(qsTr("Failed to launch gallery")); - } - } - - Menu { - id: menu - onStatusChanged: page.restartTimer(); - - MenuLayout { - MenuItem {text: qsTr("Captures in gallery"); onClicked: launchGallery(); } - MenuItem {text: qsTr("View in gallery"); enabled: available; onClicked: showInGallery(); } - } - } - - function deleteCurrentItem() { - if (!available) { - return; - } - - deleteDialog.message = currentItem.itemData.fileName; - deleteDialog.open(); - } - - QueryDialog { - id: deleteDialog - titleText: qsTr("Delete item?"); - acceptButtonText: qsTr("Yes"); - rejectButtonText: qsTr("No"); - - onStatusChanged: page.restartTimer(); - - onAccepted: { - if (!remove.remove(currentItem.itemData.url)) { - showError(qsTr("Failed to delete item")); - } - else { - postCaptureModel.remove(currentItem.itemData); - } - } - - DeleteHelper { - id: remove - } - } - - function shareCurrentItem() { - if (!available) { - return; - } - - if (!share.share(currentItem.itemData.url)) { - showError(qsTr("Failed to launch share service")); - } - } - - function addOrRemoveFavorite() { - if (!available) { - return; - } - - if (currentItem.itemData.favorite) { - if (!trackerStore.removeFromFavorites(currentItem.itemData.url)) { - showError(qsTr("Failed to remove favorite")); - } - else { - currentItem.itemData.favorite = false; - } - } - else { - if (!trackerStore.addToFavorites(currentItem.itemData.url)) { - showError(qsTr("Failed to add favorite")); - } - else { - currentItem.itemData.favorite = true; - } - } - } - - ShareHelper { - id: share - settings: platformSettings - } - - GalleryHelper { - id: gallery - settings: platformSettings - } - Rectangle { color: "black" anchors.fill: parent @@ -184,83 +84,4 @@ CameraPage { onClicked: hideTimer.running = !hideTimer.running; } } - - function restartTimer() { - hideTimer.running = true; - } - - Timer { - id: hideTimer - running: false - interval: 3000 - } - - CameraToolBar { - id: toolBar - expanded: true - manualBack: true - anchors.bottom: parent.bottom - anchors.bottomMargin: show ? 20 : -1 * (height + 20) - anchors.left: parent.left - anchors.leftMargin: 20 - opacity: 0.8 - - property bool show: deleteDialog.status == DialogStatus.Open || deleteDialog.status == DialogStatus.Opening || hideTimer.running || menu.status == DialogStatus.Open || menu.status == DialogStatus.Opening || (currentItem && currentItem.error) - - onClicked: pageStack.pop(); - - Behavior on anchors.bottomMargin { - PropertyAnimation { duration: 200; } - } - - items: [ - ToolIcon { iconId: !available ? "icon-m-toolbar-favorite-mark-dimmed-white" : currentItem.itemData.favorite ? "icon-m-toolbar-favorite-mark-white" : "icon-m-toolbar-favorite-unmark-white"; onClicked: { addOrRemoveFavorite(); page.restartTimer(); } }, - ToolIcon { iconId: available ? "icon-m-toolbar-share-white" : "icon-m-toolbar-share-dimmed-white"; onClicked: { shareCurrentItem(); page.restartTimer(); } }, - ToolIcon { iconId: available ? "icon-m-toolbar-delete-white" : "icon-m-toolbar-delete-dimmed-white"; onClicked: { deleteCurrentItem(); page.restartTimer(); } }, - ToolIcon { iconId: "icon-m-toolbar-view-menu-white"; onClicked: { menu.open(); page.restartTimer(); } } - ] - } - - Rectangle { - opacity: toolBar.opacity - anchors.top: parent.top - anchors.topMargin: toolBar.show ? 20 : -1 * (height + 20) - anchors.left: parent.left - anchors.leftMargin: 20 - anchors.right: parent.right - anchors.rightMargin: 20 - visible: toolBar.visible - height: screen.isPortrait ? toolBar.height * 2 : toolBar.height - color: toolBar.color - border.color: toolBar.border.color - radius: toolBar.radius - - Behavior on anchors.topMargin { - PropertyAnimation { duration: 200; } - } - - Flow { - width: parent.width - 40 - x: 20 - height: parent.height - - Label { - text: currentItem ? currentItem.itemData.title : "" - width: parent.width / 2 - height: parent.height - font.bold: true - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignLeft - } - - Label { - text: currentItem ? currentItem.itemData.created : "" - width: parent.width / 2 - height: parent.height - font.bold: true - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignRight - } - } - } } diff --git a/qml/PostCaptureView.qml b/qml/PostCaptureView.qml new file mode 100644 index 0000000..59924fa --- /dev/null +++ b/qml/PostCaptureView.qml @@ -0,0 +1,277 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import CameraPlus 1.0 +import com.nokia.meego 1.1 + +Item { + property bool pressed: view.currentItem ? view.currentItem.playing : false + property int policyMode: CameraResources.None + property bool available: view.currentItem ? view.currentItem.itemData.available : false + + Component.onCompleted: postCaptureModel.reload() + + ShareHelper { + id: share + settings: platformSettings + } + + GalleryHelper { + id: gallery + settings: platformSettings + } + + ListView { + id: view + anchors.fill: parent + snapMode: ListView.SnapOneItem + cacheBuffer: height * 3 + model: postCaptureModel + highlightRangeMode: ListView.StrictlyEnforceRange + + delegate: PostCaptureItem { + width: view.width + height: view.height + onClicked: hideTimer.running = !hideTimer.running + } + + onFlickingChanged: { + if (flicking && hideTimer.running) { + restartTimer() + } + } + } + + PostCaptureModel { + // TODO: this should not be active all the time + id: postCaptureModel + manufacturer: deviceInfo.manufacturer + model: deviceInfo.model + onError: { + console.log("Error populating model " + msg) + showError(qsTr("Failed to load captures")) + } + } + + Timer { + id: hideTimer + running: false + interval: 3000 + } + + CameraToolBar { + id: toolBar + expanded: true + manualBack: true + anchors.bottom: parent.bottom + anchors.bottomMargin: show ? 20 : -1 * (height + 20) + anchors.left: parent.left + anchors.leftMargin: 20 + opacity: 0.8 +// TODO: hide back button + property bool show: deleteDialog.status == DialogStatus.Open || + deleteDialog.status == DialogStatus.Opening || + hideTimer.running || menu.status == DialogStatus.Open || + menu.status == DialogStatus.Opening || + (view.currentItem && view.currentItem.error) && !view.currentItem.playing + +// TODO: +// onClicked: pageStack.pop() + + Behavior on anchors.bottomMargin { + PropertyAnimation { duration: 200; } + } + + items: [ + ToolIcon { + iconId: !available ? "icon-m-toolbar-favorite-mark-dimmed-white" : view.currentItem.itemData.favorite ? "icon-m-toolbar-favorite-mark-white" : "icon-m-toolbar-favorite-unmark-white" + onClicked: { + addOrRemoveFavorite() + restartTimer() + } + }, + ToolIcon { + iconId: available ? "icon-m-toolbar-share-white" : "icon-m-toolbar-share-dimmed-white" + onClicked: { + shareCurrentItem() + restartTimer() + } + }, + ToolIcon { + iconId: available ? "icon-m-toolbar-delete-white" : "icon-m-toolbar-delete-dimmed-white" + onClicked: { + deleteCurrentItem() + restartTimer() + } + }, + ToolIcon { + iconId: "icon-m-toolbar-view-menu-white" + onClicked: { + menu.open() + restartTimer() + } + } + ] + } + + QueryDialog { + id: deleteDialog + titleText: qsTr("Delete item?"); + acceptButtonText: qsTr("Yes"); + rejectButtonText: qsTr("No"); + + onStatusChanged: restartTimer() + + onAccepted: { + if (!remove.remove(view.currentItem.itemData.url)) { + showError(qsTr("Failed to delete item")) + } else { + postCaptureModel.remove(view.currentItem.itemData); + } + } + + DeleteHelper { + id: remove + } + } + + Menu { + id: menu + onStatusChanged: restartTimer() + + MenuLayout { + MenuItem { + text: qsTr("Captures in gallery") + onClicked: launchGallery() + } + + MenuItem { + text: qsTr("View in gallery") + enabled: available + onClicked: showInGallery() + } + } + } + + Rectangle { + opacity: toolBar.opacity + anchors.top: parent.top + anchors.topMargin: toolBar.show ? 20 : -1 * (height + 20) + anchors.left: parent.left + anchors.leftMargin: 20 + anchors.right: parent.right + anchors.rightMargin: 20 + visible: toolBar.visible + height: screen.isPortrait ? toolBar.height * 2 : toolBar.height + color: toolBar.color + border.color: toolBar.border.color + radius: toolBar.radius + + Behavior on anchors.topMargin { + PropertyAnimation { duration: 200; } + } + + Flow { + width: parent.width - 40 + x: 20 + height: parent.height + + Label { + text: view.currentItem ? view.currentItem.itemData.title : "" + width: parent.width / 2 + height: parent.height + font.bold: true + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft + } + + Label { + text: view.currentItem ? view.currentItem.itemData.created : "" + width: parent.width / 2 + height: parent.height + font.bold: true + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignRight + } + } + } + + function launchGallery() { + if (!gallery.launch()) { + showError(qsTr("Failed to launch gallery")) + } + } + + function showInGallery() { + if (!available) { + return + } + + if (!gallery.show(view.currentItem.itemUrl)) { + showError(qsTr("Failed to launch gallery")) + } + } + + function deleteCurrentItem() { + if (!available) { + return + } + + deleteDialog.message = view.currentItem.itemData.fileName + deleteDialog.open() + } + + function shareCurrentItem() { + if (!available) { + return + } + + if (!share.share(view.currentItem.itemData.url)) { + showError(qsTr("Failed to launch share service")) + } + } + + function addOrRemoveFavorite() { + if (!available) { + return + } + + if (view.currentItem.itemData.favorite) { + if (!trackerStore.removeFromFavorites(view.currentItem.itemData.url)) { + showError(qsTr("Failed to remove favorite")) + } else { + view.currentItem.itemData.favorite = false + } + } else { + if (!trackerStore.addToFavorites(view.currentItem.itemData.url)) { + showError(qsTr("Failed to add favorite")) + } else { + view.currentItem.itemData.favorite = true + } + } + } + + function restartTimer() { + hideTimer.restart() + } +} diff --git a/qml/PreviewImage.qml b/qml/PreviewImage.qml index dbc5c89..e70509e 100644 --- a/qml/PreviewImage.qml +++ b/qml/PreviewImage.qml @@ -25,31 +25,40 @@ import com.nokia.meego 1.1 import QtCamera 1.0 Image { - id: image - anchors.fill: parent - property alias animationRunning: animation.running - opacity: visible ? 1 : 0 - z: 1 + id: image + anchors.fill: parent + property alias animationRunning: animation.running - visible: opacity != 0 + visible: opacity != 0 - cache: false - fillMode: Image.PreserveAspectFit + cache: false + fillMode: Image.PreserveAspectFit - MouseArea { - anchors.fill: parent - enabled: parent.visible - } + MouseArea { + anchors.fill: parent + enabled: parent.visible + } - SequentialAnimation { - id: animation - PauseAnimation { duration: 500; alwaysRunToEnd: true } - NumberAnimation { target: preview; property: "opacity"; from: 1; to: 0; duration: 250; alwaysRunToEnd: true } + SequentialAnimation { + id: animation + PauseAnimation { + duration: 500 + alwaysRunToEnd: true } - function setPreview(preview) { - image.source = preview; - image.opacity = 1; - animation.start(); + NumberAnimation { + target: preview + property: "opacity" + from: 1 + to: 0 + duration: 250 + alwaysRunToEnd: true } + } + + function setPreview(preview) { + image.source = preview + image.opacity = 1 + animation.start() + } } diff --git a/qml/RecordingDurationLabel.qml b/qml/RecordingDurationLabel.qml new file mode 100644 index 0000000..ffac09a --- /dev/null +++ b/qml/RecordingDurationLabel.qml @@ -0,0 +1,67 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import com.nokia.meego 1.1 + +Rectangle { + property int duration + + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.bottomMargin: 20 + + color: "black" + opacity: 0.5 + width: 100 + height: 30 + + Image { + id: recordingIcon + source: "image://theme/icon-m-camera-ongoing-recording" + width: 20 + height: 20 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 5 + sourceSize.width: 20 + sourceSize.height: 20 + } + + Label { + function formatDuration(dur) { + var secs = parseInt(recordingDuration.duration) + var minutes = Math.floor(secs / 60) + var seconds = secs - (minutes * 60) + + var date = new Date() + date.setSeconds(seconds) + date.setMinutes(minutes) + return Qt.formatTime(date, "mm:ss") + } + + text: formatDuration(parent.duration) + anchors.left: recordingIcon.right + anchors.leftMargin: 5 + } +} diff --git a/qml/RecordingPage.qml b/qml/RecordingPage.qml deleted file mode 100644 index 89a76d4..0000000 --- a/qml/RecordingPage.qml +++ /dev/null @@ -1,295 +0,0 @@ -// -*- qml -*- - -/*! - * This file is part of CameraPlus. - * - * Copyright (C) 2012-2013 Mohammed Sameer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -import QtQuick 1.1 -import com.nokia.meego 1.1 -import QtCamera 1.0 -import CameraPlus 1.0 -import "data.js" as Data - -// TODO: optional resources? - -CameraPage { - id: page - activationData: ControlsActivationData {modeSelectorVisible: false} - property bool error: false - - policyMode: CameraResources.Recording - - controlsVisible: cam.running && videoMode.recording && !error - - orientationLock: PageOrientation.LockLandscape - - function policyLost() { - page.stopRecording(); - } - - function cameraError() { - error = true; - page.stopRecording(); - } - - onStatusChanged: { - if (page.status == PageStatus.Active) { - startRecording(); - } - } - - function startRecording() { - if (!pipelineManager.acquired || pipelineManager.hijacked) { - showError(qsTr("Failed to acquire needed resources.")); - pageStack.pop(undefined, true); - return; - } - - metaData.setMetaData(); - - if (!mountProtector.lock()) { - showError(qsTr("Failed to lock images directory.")); - pageStack.pop(undefined, true); - return; - } - - var file = fileNaming.videoFileName(); - var tmpFile = fileNaming.temporaryVideoFileName(); - - if (!videoMode.startRecording(file, tmpFile)) { - showError(qsTr("Failed to record video. Please restart the camera.")); - pageStack.pop(undefined, true); - mountProtector.unlock(); - } - - trackerStore.storeVideo(file); - } - - function stopRecording() { - videoMode.stopRecording(true); - mountProtector.unlock(); - // Something is fishy here but if there is an error - // and we use immediate mode then the page never gets destroyed. - pageStack.pop(undefined, error ? false : true); - } - - DisplayState { - inhibitDim: true - } - - onBatteryLow: { - if (!checkBattery()) { - page.stopRecording(); - showError(qsTr("Not enough battery to record video.")); - } - } - - ZoomCaptureButton { - id: zoomCapture - page: page - onReleased: page.stopRecording(); - } - - ZoomCaptureCancel { - anchors.fill: parent - page: page - zoomCapture: zoomCapture - } - - CaptureButton { - id: recording - anchors.right: parent.right - anchors.rightMargin: 20 - anchors.verticalCenter: parent.verticalCenter - iconSource: "image://theme/icon-m-camera-video-record" - width: 75 - height: 75 - opacity: 0.5 - - onClicked: page.stopRecording(); - visible: controlsVisible && (!settings.zoomAsShutter && keys.active) - } - - Connections { - target: Qt.application - onActiveChanged: { - if (!Qt.application.active) { - page.stopRecording(); - } - } - } - - VideoMode { - id: videoMode - camera: cam - } - - Rectangle { - anchors.top: parent.top - anchors.topMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - width: 48 - height: col.height - color: "black" - border.color: "gray" - radius: 20 - opacity: 0.5 - visible: controlsVisible - - Column { - id: col - width: parent.width - spacing: 5 - - Indicator { - id: resolutionIndicator - source: "image://theme/" + Data.videoIcon(settings.videoResolution); - } - - Indicator { - id: wbIndicator - source: visible ? "image://theme/" + Data.wbIcon(settings.videoWhiteBalance) + "-screen" : "" - visible: settings.videoWhiteBalance != WhiteBalance.Auto - } - - Indicator { - id: cfIndicator - source: "image://theme/" + Data.cfIcon(settings.videoColorFilter) + "-screen" - visible: settings.videoColorFilter != ColorTone.Normal - } - - Indicator { - id: gpsIndicator - visible: settings.useGps - source: "image://theme/icon-m-camera-location" - - PropertyAnimation on opacity { - easing.type: Easing.OutSine - loops: Animation.Infinite - from: 0.2 - to: 1.0 - duration: 1000 - running: settings.useGps && !positionSource.position.longitudeValid - alwaysRunToEnd: true - } - } - } - } - - Rectangle { - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.rightMargin: 20 - anchors.bottomMargin: 20 - - visible: controlsVisible - - color: "black" - opacity: 0.5 - width: 100 - height: 30 - - Timer { - id: recordingDuration - - property int duration: 0 - - running: videoMode.recording - interval: 1000 - repeat: true - - onTriggered: { - duration = duration + 1; - if (duration == 3600) { - page.stopRecording(); - showError(qsTr("Maximum recording time reached.")); - } - else if (!checkDiskSpace()) { - page.stopRecording(); - showError(qsTr("Not enough space to continue recording.")); - } - } - } - - Image { - id: recordingIcon - source: "image://theme/icon-m-camera-ongoing-recording" - width: 20 - height: 20 - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: 5 - sourceSize.width: 20 - sourceSize.height: 20 - } - - Label { - function formatDuration(dur) { - var secs = parseInt(recordingDuration.duration); - var minutes = Math.floor(secs / 60); - var seconds = secs - (minutes * 60); - - var date = new Date(); - date.setSeconds(seconds); - date.setMinutes(minutes); - return Qt.formatTime(date, "mm:ss"); - } - - id: durationLabel - text: formatDuration(recordingDuration.duration); - anchors.left: recordingIcon.right - anchors.leftMargin: 5 - } - } - - CameraToolBar { - id: toolBar - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - opacity: 0.5 - targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5) - visible: controlsVisible - expanded: settings.showToolBar - onExpandedChanged: settings.showToolBar = expanded; - - items: [ - VideoTorchButton { - camera: cam - }, - VideoEvCompButton { - onClicked: toolBar.push(items); - }, - VideoWhiteBalanceButton { - onClicked: toolBar.push(items); - }, - VideoColorFilterButton { - onClicked: toolBar.push(items); - }, - VideoMuteButton { - }, - ToolIcon { - iconSource: "image://theme/icon-m-toolbar-view-menu-white" - onClicked: openFile("VideoSettingsPage.qml"); - } - ] - } -} diff --git a/qml/SectionHeader.qml b/qml/SectionHeader.qml index ec7c784..ae39e4d 100644 --- a/qml/SectionHeader.qml +++ b/qml/SectionHeader.qml @@ -24,25 +24,25 @@ import QtQuick 1.1 import com.nokia.meego 1.1 Row { - id: root + id: root - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 10 - anchors.rightMargin: 10 - spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 10 + anchors.rightMargin: 10 + spacing: 10 - property alias text: label.text + property alias text: label.text - Label { - id: label - verticalAlignment: Text.AlignVCenter - } + Label { + id: label + verticalAlignment: Text.AlignVCenter + } - Rectangle { - color: "darkgray" - height: 2 - width: parent.width - label.width - 20 - anchors.verticalCenter: parent.verticalCenter - } + Rectangle { + color: "darkgray" + height: 2 + width: parent.width - label.width - 20 + anchors.verticalCenter: parent.verticalCenter + } } diff --git a/qml/ControlsActivationData.qml b/qml/SettingsView.qml similarity index 71% rename from qml/ControlsActivationData.qml rename to qml/SettingsView.qml index 30d785d..41b8773 100644 --- a/qml/ControlsActivationData.qml +++ b/qml/SettingsView.qml @@ -21,16 +21,16 @@ */ import QtQuick 1.1 +import QtCamera 1.0 +import CameraPlus 1.0 -QtObject { - property bool zoomBarVisible: true - property bool modeSelectorVisible: true - property bool standbyVisible: true +Item { + property int policyMode: settings.mode == Camera.VideoMode ? CameraResources.Video + : CameraResources.Image -/* -// TODO: - property bool focusReticleVisible: true - property bool captureButtonVisible: true - property bool viewfinderEnabled: true -*/ + Loader { + id: loader + anchors.fill: parent + source: settings.mode == Camera.VideoMode ? Qt.resolvedUrl("VideoSettings.qml") : Qt.resolvedUrl("ImageSettings.qml") + } } diff --git a/qml/TextSwitch.qml b/qml/TextSwitch.qml index 3c5b89e..2744d17 100644 --- a/qml/TextSwitch.qml +++ b/qml/TextSwitch.qml @@ -24,24 +24,24 @@ import QtQuick 1.1 import com.nokia.meego 1.1 Item { - property alias text: label.text - property alias checked: switchComponent.checked - width: parent.width - height: switchComponent.height + property alias text: label.text + property alias checked: switchComponent.checked + width: parent.width + height: switchComponent.height - Text { - property Style platformStyle: LabelStyle {} + Text { + property Style platformStyle: LabelStyle {} - id: label - anchors.left: parent.left - font.family: platformStyle.fontFamily - font.pixelSize: platformStyle.fontPixelSize - color: platformStyle.textColor - wrapMode: Text.Wrap - } + id: label + anchors.left: parent.left + font.family: platformStyle.fontFamily + font.pixelSize: platformStyle.fontPixelSize + color: platformStyle.textColor + wrapMode: Text.Wrap + } - Switch { - id: switchComponent - anchors.right: parent.right - } + Switch { + id: switchComponent + anchors.right: parent.right + } } diff --git a/qml/VideoOverlay.qml b/qml/VideoOverlay.qml new file mode 100644 index 0000000..1eedaf8 --- /dev/null +++ b/qml/VideoOverlay.qml @@ -0,0 +1,300 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import com.nokia.meego 1.1 +import QtCamera 1.0 +import CameraPlus 1.0 +import "data.js" as Data + +Item { + id: overlay + property bool recording: false + + property Camera cam + property bool animationRunning: false + property int policyMode: recording == true ? CameraResources.Recording : CameraResources.Video + property bool controlsVisible: !animationRunning && cam.running && dimmer.opacity == 0.0 + && !cameraMode.busy +// TODO: + property bool pressed: overlay.recording || capture.pressed || + zoomSlider.pressed || modeButton.pressed + + signal previewAvailable(string uri) + + anchors.fill: parent + + VideoMode { + id: videoMode + camera: cam + onPreviewAvailable: overlay.previewAvailable(preview) + } + + ZoomSlider { + id: zoomSlider + camera: cam + anchors.top: parent.top + anchors.topMargin: 0 + anchors.horizontalCenter: parent.horizontalCenter + visible: controlsVisible + } + + ModeButton { + id: modeButton + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.bottomMargin: 20 + visible: controlsVisible && !overlay.recording + } + + ZoomCaptureButton { + id: zoomCapture + onReleased: overlay.toggleRecording() + } + + ZoomCaptureCancel { + anchors.fill: parent + zoomCapture: zoomCapture + } + + CaptureButton { + id: capture + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.verticalCenter: parent.verticalCenter + iconSource: overlay.recording ? "image://theme/icon-m-camera-video-record" : "image://theme/icon-m-camera-video-record" + width: 75 + height: 75 + opacity: 0.5 + + onClicked: overlay.toggleRecording() + + visible: controlsVisible && (!settings.zoomAsShutter && keys.active) + } + + CameraToolBar { + id: toolBar + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + opacity: 0.5 + targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5) + visible: controlsVisible + expanded: settings.showToolBar + onExpandedChanged: settings.showToolBar = expanded; + + items: [ + VideoTorchButton { + camera: cam + }, + VideoSceneButton { +// TODO: hide when recording + onClicked: toolBar.push(items) + }, + VideoEvCompButton { + onClicked: toolBar.push(items) + }, + VideoWhiteBalanceButton { + onClicked: toolBar.push(items) + }, + VideoColorFilterButton { + onClicked: toolBar.push(items) + }, + VideoMuteButton { + } + ] + } + + Rectangle { + anchors.top: parent.top + anchors.topMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + width: 48 + height: col.height + color: "black" + border.color: "gray" + radius: 20 + opacity: 0.5 + visible: controlsVisible + + Column { + id: col + width: parent.width + spacing: 5 + + Indicator { + id: resolutionIndicator + source: "image://theme/" + Data.videoIcon(settings.videoResolution) + } + + Indicator { + id: wbIndicator + source: visible ? "image://theme/" + Data.wbIcon(settings.videoWhiteBalance) + "-screen" : "" + visible: settings.videoWhiteBalance != WhiteBalance.Auto + } + + Indicator { + id: cfIndicator + source: "image://theme/" + Data.cfIcon(settings.videoColorFilter) + "-screen" + visible: settings.videoColorFilter != ColorTone.Normal + } + + Indicator { + id: gpsIndicator + visible: settings.useGps + source: "image://theme/icon-m-camera-location" + + PropertyAnimation on opacity { + easing.type: Easing.OutSine + loops: Animation.Infinite + from: 0.2 + to: 1.0 + duration: 1000 + running: settings.useGps && !positionSource.position.longitudeValid + alwaysRunToEnd: true + } + } + } + } + + DisplayState { + inhibitDim: overlay.recording + } + + Connections { + target: Qt.application + onActiveChanged: { + if (!Qt.application.active && overlay.recording) { + overlay.stopRecording() + } + } + } + + Timer { + id: recordingDuration + property int duration: 0 + running: overlay.recording + interval: 1000 + repeat: true + + onTriggered: { + duration = duration + 1 + + if (duration == 3600) { + overlay.stopRecording() + showError(qsTr("Maximum recording time reached.")) + } else if (!checkDiskSpace()) { + page.stopRecording() + showError(qsTr("Not enough space to continue recording.")) + } + + } + } + + RecordingDurationLabel { + visible: overlay.recording + duration: recordingDuration.duration + } + + function doStartRecording() { + if (!overlay.recording) { + return + } + + if (!pipelineManager.acquired || pipelineManager.hijacked) { + showError(qsTr("Failed to acquire needed resources.")) + overlay.recording = false + return + } + + metaData.setMetaData() + + if (!mountProtector.lock()) { + showError(qsTr("Failed to lock images directory.")) + overlay.recording = false + return + } + + var file = fileNaming.videoFileName() + var tmpFile = fileNaming.temporaryVideoFileName() + + if (!videoMode.startRecording(file, tmpFile)) { + showError(qsTr("Failed to record video. Please restart the camera.")) + mountProtector.unlock() + overlay.recording = false + return + } + + trackerStore.storeVideo(file); + } + + function startRecording() { + if (!fileSystem.available) { + showError(qsTr("Camera cannot record videos in mass storage mode.")) + } else if (!checkBattery()) { + showError(qsTr("Not enough battery to record video.")) + } else if (!checkDiskSpace()) { + showError(qsTr("Not enough space to record video.")) + } else { + recordingDuration.duration = 0 + overlay.recording = true + doStartRecording() + } + } + + function stopRecording() { + videoMode.stopRecording(true) + mountProtector.unlock() + overlay.recording = false + } + + function toggleRecording() { + if (overlay.recording) { + overlay.stopRecording() + } else { + overlay.startRecording() + } + } + + function cameraError() { + overlay.stopRecording() + } + + function policyLost() { + overlay.stopRecording() + } + + function batteryLow() { + if (!overlay.recording) { + return + } + + if (!checkBattery()) { + overlay.stopRecording() + showError(qsTr("Not enough battery to record video.")) + } + } + +} diff --git a/qml/VideoPage.qml b/qml/VideoPage.qml deleted file mode 100644 index c2dd5f8..0000000 --- a/qml/VideoPage.qml +++ /dev/null @@ -1,211 +0,0 @@ -// -*- qml -*- - -/*! - * This file is part of CameraPlus. - * - * Copyright (C) 2012-2013 Mohammed Sameer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -import QtQuick 1.1 -import com.nokia.meego 1.1 -import QtCamera 1.0 -import CameraPlus 1.0 -import "data.js" as Data - -CameraPage { - id: page - - policyMode: CameraResources.Video - - controlsVisible: cam.running && !videoMode.recording && videoMode.canCapture && !cameraMode.busy && dimmer.opacity == 0.0 && !previewAnimationRunning - orientationLock: PageOrientation.LockLandscape - - property Item settingsDialog: null - - function startRecording() { - if (!fileSystem.available) { - showError(qsTr("Camera cannot record videos in mass storage mode.")); - return; - } - - if (!checkBattery()) { - showError(qsTr("Not enough battery to record video.")); - return; - } - - if (!checkDiskSpace()) { - showError(qsTr("Not enough space to record video.")); - return; - } - - openFileNow("RecordingPage.qml"); - } - - ZoomCaptureButton { - id: zoomCapture - page: page - onReleased: page.startRecording(); - } - - ZoomCaptureCancel { - anchors.fill: parent - page: page - zoomCapture: zoomCapture - } - - CaptureButton { - id: recording - anchors.right: parent.right - anchors.rightMargin: 20 - anchors.verticalCenter: parent.verticalCenter - iconSource: "image://theme/icon-m-camera-video-record" - width: 75 - height: 75 - opacity: 0.5 - - onClicked: startRecording(); - - visible: controlsVisible && (!settings.zoomAsShutter && keys.active) - } - - VideoMode { - id: videoMode - camera: cam - onPreviewAvailable: { - page.setPreview(preview); - } - } - - Rectangle { - anchors.top: parent.top - anchors.topMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - width: 48 - height: col.height - color: "black" - border.color: "gray" - radius: 20 - opacity: 0.5 - visible: controlsVisible - - Column { - id: col - width: parent.width - spacing: 5 - - Indicator { - id: resolutionIndicator - source: "image://theme/" + Data.videoIcon(settings.videoResolution); - } - - Indicator { - id: wbIndicator - source: visible ? "image://theme/" + Data.wbIcon(settings.videoWhiteBalance) + "-screen" : "" - visible: settings.videoWhiteBalance != WhiteBalance.Auto - } - - Indicator { - id: cfIndicator - source: "image://theme/" + Data.cfIcon(settings.videoColorFilter) + "-screen" - visible: settings.videoColorFilter != ColorTone.Normal - } - - Indicator { - id: gpsIndicator - visible: settings.useGps - source: "image://theme/icon-m-camera-location" - - PropertyAnimation on opacity { - easing.type: Easing.OutSine - loops: Animation.Infinite - from: 0.2 - to: 1.0 - duration: 1000 - running: settings.useGps && !positionSource.position.longitudeValid - alwaysRunToEnd: true - } - } - } - } - - Button { - id: cameraRoll - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: 20 - anchors.rightMargin: 20 - width: 56 - height: 56 - - opacity: 0.5 - iconSource: "image://theme/icon-m-camera-roll" - onClicked: openFile("PostCapturePage.qml"); - visible: controlsVisible - } - - CameraToolBar { - id: toolBar - anchors.bottom: parent.bottom - anchors.bottomMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 20 - opacity: 0.5 - targetWidth: parent.width - (anchors.leftMargin * 2) - (66 * 1.5) - visible: controlsVisible - expanded: settings.showToolBar - onExpandedChanged: settings.showToolBar = expanded; - - items: [ - VideoTorchButton { - camera: cam - }, - VideoSceneButton { - onClicked: toolBar.push(items); - }, - VideoEvCompButton { - onClicked: toolBar.push(items); - }, - VideoWhiteBalanceButton { - onClicked: toolBar.push(items); - }, - VideoColorFilterButton { - onClicked: toolBar.push(items); - }, - VideoMuteButton { - }, - ToolIcon { - iconSource: "image://theme/icon-m-toolbar-view-menu-white" - onClicked: openSettings(); - } - ] - } - - function openSettings() { - if (!settingsDialog) { - settingsDialog = videoSettingsDialog.createObject(page); - } - - settingsDialog.open(); - } - - Component { - id: videoSettingsDialog - - VideoSettingsDialog { } - } -} diff --git a/qml/VideoPlayerPage.qml b/qml/VideoPlayerPage.qml index 51684a3..490e6b6 100644 --- a/qml/VideoPlayerPage.qml +++ b/qml/VideoPlayerPage.qml @@ -27,123 +27,109 @@ import CameraPlus 1.0 // TODO: error reporting -CameraPage { - id: page - - property bool popTwice: false - controlsVisible: false - policyMode: CameraResources.None - activationData: ControlsActivationData {standbyVisible: false} - - property alias source: video.source - - function play() { - video.play(); +Item { + id: page + + signal finished + property alias source: video.source + + function play() { + video.play() + } + + MouseArea { + anchors.top: parent.top + anchors.bottom: toolBar.top + anchors.left: parent.left + anchors.right: parent.right + + onClicked: toolBar.show = !toolBar.show + } + + Timer { + id: hideTimer + running: toolBar.show + interval: 3000 + onTriggered: toolBar.show = false + } + + Video { + id: video + anchors.fill: parent + + function toggle() { + if (!video.paused) { + video.pause() + } else { + page.play() + } } - MouseArea { - anchors.top: parent.top - anchors.bottom: toolBar.top - anchors.left: parent.left - anchors.right: parent.right + onStopped: page.finished() + } - onClicked: toolBar.show = !toolBar.show + Connections { + target: Qt.application + onActiveChanged: { + if (!Qt.application.active) { + video.stop() + } } + } - Timer { - id: hideTimer - running: toolBar.show - interval: 3000 - onTriggered: toolBar.show = false; - } + CameraToolBar { + id: toolBar - Video { - id: video - anchors.fill: parent - - function toggle() { - if (!video.paused) { - video.pause(); - } - else { - page.play(); - } - } + property bool show: true - onStopped: { - source = ""; - pageStack.pop(undefined, true); + manualBack: true + expanded: true + anchors.bottom: parent.bottom + anchors.bottomMargin: show ? 20 : -1 * (height + 20) + anchors.left: parent.left + anchors.leftMargin: 20 + opacity: 0.5 - if (page.popTwice) { - pageStack.pop(undefined); - } - } - } - - Connections { - target: Qt.application - onActiveChanged: { - if (!Qt.application.active) { - video.stop(); - } - } + Behavior on anchors.bottomMargin { + PropertyAnimation { duration: 200; } } - CameraToolBar { - id: toolBar + items: [ + ToolIcon { + iconId: "icon-m-toolbar-mediacontrol-stop-white" + onClicked: video.stop() + }, + Slider { + id: slider + height: toolBar.height + anchors.verticalCenter: parent.verticalCenter + + platformStyle: SliderStyle { + handleBackground: "" + handleBackgroundPressed: "" + } - property bool show: true + minimumValue: 0 + maximumValue: video.duration + value: video.position + orientation: Qt.Horizontal - manualBack: true - expanded: true - anchors.bottom: parent.bottom - anchors.bottomMargin: show ? 20 : -1 * (height + 20) - anchors.left: parent.left - anchors.leftMargin: 20 - opacity: 0.5 + onPressedChanged: { + if (!slider.pressed) { + video.position = slider.value + } - Behavior on anchors.bottomMargin { - PropertyAnimation { duration: 200; } + hideTimer.restart() } - + }, + ToolIcon { + id: control + iconId: !video.paused ? "icon-m-toolbar-mediacontrol-pause-white" : "icon-m-toolbar-mediacontrol-play-white" onClicked: { - page.popTwice = true; - video.stop(); + video.toggle() + hideTimer.restart() } - - items: [ - ToolIcon { iconId: "icon-m-toolbar-mediacontrol-stop-white"; onClicked: { video.stop(); } }, - Slider { - id: slider - height: toolBar.height - anchors.verticalCenter: parent.verticalCenter - - platformStyle: SliderStyle { - handleBackground: "" - handleBackgroundPressed: "" - } - - minimumValue: 0 - maximumValue: video.duration - value: video.position - orientation: Qt.Horizontal - - onPressedChanged: { - if (!slider.pressed) { - video.position = slider.value; - } - - hideTimer.restart(); - } - }, - ToolIcon { - id: control - iconId: !video.paused ? "icon-m-toolbar-mediacontrol-pause-white" : "icon-m-toolbar-mediacontrol-play-white" - onClicked: { - video.toggle(); - hideTimer.restart(); - } - } - ] - } + } + ] + } } diff --git a/qml/VideoResolutionSettings.qml b/qml/VideoResolutionSettings.qml index 51503ef..e80be20 100644 --- a/qml/VideoResolutionSettings.qml +++ b/qml/VideoResolutionSettings.qml @@ -24,29 +24,28 @@ import QtQuick 1.1 import com.nokia.meego 1.1 Column { - spacing: 10 - - SectionHeader { - text: qsTr("Resolution"); - } + spacing: 10 + SectionHeader { + text: qsTr("Resolution") + } - ButtonRow { - width: parent.width - enabled: cam.idle - exclusive: false + ButtonRow { + width: parent.width + enabled: cam.idle + exclusive: false - Repeater { - id: resolutions + Repeater { + id: resolutions - model: videoSettings.resolutions + model: videoSettings.resolutions - delegate: Button { - font.capitalization: Font.Capitalize - text: qsTr("%1 %2").arg(resolutionName).arg(resolution); - checked: settings.videoResolution == resolutionName; - onClicked: settings.videoResolution = resolutionName; - } - } + delegate: Button { + font.capitalization: Font.Capitalize + text: qsTr("%1 %2").arg(resolutionName).arg(resolution) + checked: settings.videoResolution == resolutionName + onClicked: settings.videoResolution = resolutionName + } } + } } diff --git a/qml/VideoSettings.qml b/qml/VideoSettings.qml new file mode 100644 index 0000000..c7a554a --- /dev/null +++ b/qml/VideoSettings.qml @@ -0,0 +1,50 @@ +// -*- qml -*- + +/*! + * This file is part of CameraPlus. + * + * Copyright (C) 2012-2013 Mohammed Sameer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import QtQuick 1.1 +import com.nokia.meego 1.1 +import QtCamera 1.0 + +Flickable { + contentHeight: col.height + anchors.fill: parent + anchors.margins: 10 + + Column { + id: col + width: parent.width + spacing: 10 + + Label { + font.pixelSize: 36 + text: qsTr("Video settings") + } + + VideoResolutionSettings { + width: parent.width + } + + CameraSettings { + anchors.horizontalCenter: parent.horizontalCenter + } + } +} diff --git a/qml/VideoSettingsDialog.qml b/qml/VideoSettingsDialog.qml deleted file mode 100644 index b536706..0000000 --- a/qml/VideoSettingsDialog.qml +++ /dev/null @@ -1,83 +0,0 @@ -// -*- qml -*- - -/*! - * This file is part of CameraPlus. - * - * Copyright (C) 2012-2013 Mohammed Sameer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -import QtQuick 1.1 -import com.nokia.meego 1.1 -import QtCamera 1.0 - -Dialog { - id: dialog - - content: item - - Connections { - target: Qt.application - onActiveChanged: { - if (!Qt.application.active) { - dialog.close(); - } - } - } - - onStatusChanged: { - if (status == DialogStatus.Open) { - cam.renderingEnabled = false; - } - else if (status == DialogStatus.Closing) { - cam.renderingEnabled = true; - } - } - - Item { - id: item - width: parent.width - height: root.height - - - Flickable { - id: flickable - anchors.fill: parent - anchors.margins: 10 - contentHeight: col.height - - Column { - id: col - - width: parent.width - spacing: 10 - - Label { - font.pixelSize: 36 - text: qsTr("Video settings"); - } - - VideoResolutionSettings { - width: parent.width - } - - CameraSettings { - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - } -} diff --git a/qml/ZoomCaptureButton.qml b/qml/ZoomCaptureButton.qml index b2bef31..7b2763e 100644 --- a/qml/ZoomCaptureButton.qml +++ b/qml/ZoomCaptureButton.qml @@ -25,56 +25,55 @@ import com.nokia.meego 1.1 import CameraPlus 1.0 Item { - id: zoomHandler - property Item page - property bool zoomPressed: false + id: zoomHandler + property bool zoomPressed: false - signal pressed(); - signal released(); + signal pressed() + signal released() - property bool active: settings.zoomAsShutter && page.status == PageStatus.Active && Qt.application.active + property bool active: settings.zoomAsShutter && Qt.application.active - function handlePress() { - if (!zoomHandler.active || zoomHandler.zoomPressed) { - return; - } - - zoomHandler.zoomPressed = true; - zoomHandler.pressed(); + function handlePress() { + if (!zoomHandler.active || zoomHandler.zoomPressed) { + return } - function handleRelease() { - if (!zoomHandler.active || !zoomHandler.zoomPressed) { - return; - } - - zoomHandler.zoomPressed = false; + zoomHandler.zoomPressed = true + zoomHandler.pressed() + } - zoomHandler.released(); + function handleRelease() { + if (!zoomHandler.active || !zoomHandler.zoomPressed) { + return } - Connections { - id: zoomConnection - target: keys + zoomHandler.zoomPressed = false - onActiveChanged: { - if (!zoomConnection.active) { - zoomHandler.zoomPressed = false; - } - } + zoomHandler.released() + } - onVolumeUpPressed: zoomHandler.handlePress(); - onVolumeDownPressed: zoomHandler.handlePress(); - onVolumeUpReleased: zoomHandler.handleRelease(); - onVolumeDownReleased: zoomHandler.handleRelease(); + Connections { + id: zoomConnection + target: keys + + onActiveChanged: { + if (!zoomConnection.active) { + zoomHandler.zoomPressed = false + } } - Connections { - target: Qt.application - onActiveChanged: { - if (!Qt.application.active) { - zoomHandler.zoomPressed = false; - } - } + onVolumeUpPressed: zoomHandler.handlePress() + onVolumeDownPressed: zoomHandler.handlePress() + onVolumeUpReleased: zoomHandler.handleRelease() + onVolumeDownReleased: zoomHandler.handleRelease() + } + + Connections { + target: Qt.application + onActiveChanged: { + if (!Qt.application.active) { + zoomHandler.zoomPressed = false + } } + } } diff --git a/qml/ZoomCaptureCancel.qml b/qml/ZoomCaptureCancel.qml index ac33496..d89ee04 100644 --- a/qml/ZoomCaptureCancel.qml +++ b/qml/ZoomCaptureCancel.qml @@ -25,43 +25,42 @@ import com.nokia.meego 1.1 import CameraPlus 1.0 MouseArea { - id: zoomCancel - property Item page - property Item zoomCapture + id: zoomCancel + property Item zoomCapture - signal canceled + signal canceled - z: 100 - enabled: zoomCapture.zoomPressed + z: 100 + enabled: zoomCapture.zoomPressed - onPressed: { - zoomCancel.zoomCapture.zoomPressed = false; - zoomCancel.canceled(); - } + onPressed: { + zoomCancel.zoomCapture.zoomPressed = false + zoomCancel.canceled() + } - Rectangle { - anchors.top: parent.top - opacity: parent.enabled ? 0.5 : 0 - anchors.topMargin: 20 - anchors.horizontalCenter: parent.horizontalCenter - visible: opacity > 0 - height: label.height * 2 - width: parent.width * 0.7 - color: "black" - border.color: "gray" - radius: 20 + Rectangle { + anchors.top: parent.top + opacity: parent.enabled ? 0.5 : 0 + anchors.topMargin: 20 + anchors.horizontalCenter: parent.horizontalCenter + visible: opacity > 0 + height: label.height * 2 + width: parent.width * 0.7 + color: "black" + border.color: "gray" + radius: 20 - Behavior on opacity { - PropertyAnimation { duration: 100; } - } + Behavior on opacity { + PropertyAnimation { duration: 100; } + } - Label { - id: label - anchors.verticalCenter: parent.verticalCenter - width: parent.width - text: qsTr("Tap anywhere to cancel"); - font.pixelSize: 24 - horizontalAlignment: Text.AlignHCenter - } + Label { + id: label + anchors.verticalCenter: parent.verticalCenter + width: parent.width + text: qsTr("Tap anywhere to cancel") + font.pixelSize: 24 + horizontalAlignment: Text.AlignHCenter } + } } diff --git a/qml/ZoomSlider.qml b/qml/ZoomSlider.qml index c1b72b3..6087ac8 100644 --- a/qml/ZoomSlider.qml +++ b/qml/ZoomSlider.qml @@ -25,78 +25,79 @@ import com.nokia.meego 1.1 import QtCamera 1.0 Slider { - id: slider - property Camera camera: null + id: slider + property Camera camera: null - platformStyle: SliderStyle { - handleBackground: "" - handleBackgroundPressed: "" - } + platformStyle: SliderStyle { + handleBackground: "" + handleBackgroundPressed: "" + } - Binding { - target: camera.zoom - property: "value" - value: slider.value - } + Binding { + target: camera.zoom + property: "value" + value: slider.value + } - Connections { - target: camera - onModeChanged: slider.value = camera.zoom.minimum; - } + Connections { + target: camera + onModeChanged: slider.value = camera.zoom.minimum; + } - Connections { - target: keys + Connections { + target: keys - onVolumeUpPressed: { - if (settings.zoomAsShutter) { - return; - } + onVolumeUpPressed: { + if (settings.zoomAsShutter) { + return; + } - slider.value = Math.min(slider.value + slider.stepSize, slider.maximumValue); - hackTimer.running = true; - } + slider.value = Math.min(slider.value + slider.stepSize, slider.maximumValue) + hackTimer.running = true + } - onVolumeDownPressed: { - if (settings.zoomAsShutter) { - return; - } + onVolumeDownPressed: { + if (settings.zoomAsShutter) { + return; + } - slider.value = Math.max(slider.value - slider.stepSize, slider.minimumValue); - hackTimer.running = true; - } + slider.value = Math.max(slider.value - slider.stepSize, slider.minimumValue) + hackTimer.running = true } + } - orientation: Qt.Horizontal - width: 500 - height: 50 - stepSize:0.1 - value: camera.zoom.value - minimumValue: camera.zoom.minimum - maximumValue: camera.zoom.maximum + orientation: Qt.Horizontal + width: 500 + height: 50 + stepSize:0.1 + value: camera.zoom.value + minimumValue: camera.zoom.minimum + maximumValue: camera.zoom.maximum - state: "hidden" - states: [ + state: "hidden" + states: [ State { - name: "visible" - when: slider.pressed || hackTimer.running - PropertyChanges { target: slider; opacity: 1.0 } + name: "visible" + when: slider.pressed || hackTimer.running + PropertyChanges { target: slider; opacity: 1.0 } }, State { - name: "hidden" - when: !slider.pressed - PropertyChanges { target: slider; opacity: 0.2 } - }] - - transitions: Transition { - to: "hidden" - SequentialAnimation { - PauseAnimation { duration: 2000 } - NumberAnimation { target: slider; property: "opacity"; duration: 250 } - } + name: "hidden" + when: !slider.pressed + PropertyChanges { target: slider; opacity: 0.2 } } + ] - Timer { - id: hackTimer - interval: 1 - } + transitions: Transition { + to: "hidden" + SequentialAnimation { + PauseAnimation { duration: 2000 } + NumberAnimation { target: slider; property: "opacity"; duration: 250 } + } + } + + Timer { + id: hackTimer + interval: 1 + } } diff --git a/qml/main.qml b/qml/main.qml index 4085bac..6693eb5 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -26,436 +26,252 @@ import com.nokia.extras 1.1 import QtCamera 1.0 import CameraPlus 1.0 import QtMobility.location 1.2 - +//import QtCamera 1.0 // TODO: flash not ready (battery low or flash not ready message) Window { id: root + property alias camera: cam +// property bool cameraVisible: mainView.currentIndex == 1 - property alias dimmer: camDimmer + VisualItemModel { + id: mainModel - PageStack { - id: pageStack - anchors.fill: parent + SettingsView { + width: mainView.width + height: mainView.height + } + + CameraView { + id: cam + width: mainView.width + height: mainView.height + } + + PostCaptureView { + width: mainView.width + height: mainView.height + } } - MouseArea { - anchors.fill: parent - enabled: pageStack.busy + ListView { + id: mainView + LayoutMirroring.enabled: false + anchors.fill: parent + orientation: ListView.Horizontal + model: mainModel + snapMode: ListView.SnapOneItem + highlightRangeMode: ListView.StrictlyEnforceRange + boundsBehavior: Flickable.StopAtBounds + currentIndex: 1 + interactive: !currentItem.pressed + } + + Component.onCompleted: { + screen.setAllowedOrientations(Screen.Landscape) + theme.inverted = true + platformSettings.init() + // TODO: hardcoding device id + root.resetCamera(0, settings.mode) } PlatformSettings { - id: platformSettings + id: platformSettings } - Component.onCompleted: { - platformSettings.init(); - theme.inverted = true; - // TODO: hardcoding device id - root.resetCamera(0, settings.mode); + Settings { + id: settings } - function showError(msg) { - error.text = msg; - error.show(); + PipelineManager { + id: pipelineManager + camera: cam + currentItem: mainView.currentItem } function resetCamera(deviceId, mode) { - if (!cam.reset(deviceId, mode)) { - showError(qsTr("Failed to set camera device and mode. Please restart the application.")); - } + if (!cam.reset(deviceId, mode)) { + showError(qsTr("Failed to set camera device and mode. Please restart the application.")) + } + } + + function showError(msg) { + error.text = msg + error.show() + } + + property alias dimmer: camDimmer + + PageStack { + id: pageStack + anchors.fill: parent + } + + MouseArea { + anchors.fill: parent + enabled: pageStack.busy } PositionSource { - // NOTE: The source will not reset the position when we lose the signal. - // This shouldn't be a big problem as we are course enough. - // If we ever need street level updates then this will be an issue. - id: positionSource - active: settings.useGps - // TODO: we cannot bind to cam.running because camera will stop - // when the connection dialog pops up and we end up with an infinite loop - // active: cam.running && settings.useGps - onPositionChanged: geocode.search(position.coordinate.longitude, position.coordinate.latitude); + // NOTE: The source will not reset the position when we lose the signal. + // This shouldn't be a big problem as we are course enough. + // If we ever need street level updates then this will be an issue. + id: positionSource + active: settings.useGps + // TODO: we cannot bind to cam.running because camera will stop + // when the connection dialog pops up and we end up with an infinite loop + // active: cam.running && settings.useGps + onPositionChanged: geocode.search(position.coordinate.longitude, position.coordinate.latitude) } MetaData { - id: metaData - camera: cam - manufacturer: deviceInfo.manufacturer - model: deviceInfo.model - country: geocode.country - city: geocode.city - suburb: geocode.suburb - longitude: positionSource.position.coordinate.longitude - longitudeValid: positionSource.position.longitudeValid && settings.useGps - latitude: positionSource.position.coordinate.latitude - latitudeValid: positionSource.position.latitudeValid && settings.useGps - elevation: positionSource.position.coordinate.altitude - elevationValid: positionSource.position.altitudeValid && settings.useGps - orientation: orientation.orientation - artist: settings.creatorName - captureDirection: compass.direction - captureDirectionValid: compass.directionValid - horizontalError: positionSource.position.horizontalAccuracy - horizontalErrorValid: positionSource.position.horizontalAccuracyValid && settings.useGps - dateTimeEnabled: true + id: metaData + camera: cam + manufacturer: deviceInfo.manufacturer + model: deviceInfo.model + country: geocode.country + city: geocode.city + suburb: geocode.suburb + longitude: positionSource.position.coordinate.longitude + longitudeValid: positionSource.position.longitudeValid && settings.useGps + latitude: positionSource.position.coordinate.latitude + latitudeValid: positionSource.position.latitudeValid && settings.useGps + elevation: positionSource.position.coordinate.altitude + elevationValid: positionSource.position.altitudeValid && settings.useGps + orientation: orientation.orientation + artist: settings.creatorName + captureDirection: compass.direction + captureDirectionValid: compass.directionValid + horizontalError: positionSource.position.horizontalAccuracy + horizontalErrorValid: positionSource.position.horizontalAccuracyValid && settings.useGps + dateTimeEnabled: true } Orientation { - id: orientation - active: cam.running + id: orientation + active: cam.running } Compass { - id: compass - active: cam.running + id: compass + active: cam.running } ReverseGeocode { - id: geocode - active: cam.running && settings.useGps && settings.useGeotags - } - - PipelineManager { - id: pipelineManager - camera: cam + id: geocode + active: cam.running && settings.useGps && settings.useGeotags } DeviceInfo { - id: deviceInfo + id: deviceInfo } FSMonitor { - id: fileSystem + id: fileSystem } InfoBanner { - id: error - } - - Settings { - id: settings + id: error } FileNaming { - id: fileNaming - imageSuffix: cam.imageSuffix - videoSuffix: cam.videoSuffix + id: fileNaming + imageSuffix: cam.imageSuffix + videoSuffix: cam.videoSuffix } MountProtector { - id: mountProtector - path: fileNaming.path - } - - BatteryInfo { - id: batteryMonitor - active: cam.running - - function check() { - if (!checkBattery()) { - pageStack.currentPage.batteryLow(); - } - } - - onChargingChanged: { - batteryMonitor.check(); - } - - onCriticalChanged: { - batteryMonitor.check(); - } - } - - function replacePage(file) { - pageStack.replace(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}, true); + id: mountProtector + path: fileNaming.path } - function openFile(file) { - pageStack.push(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}); - } - - function openFileNow(file) { - pageStack.push(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}, true); + TrackerStore { + id: trackerStore + active: cam.running + manufacturer: deviceInfo.manufacturer + model: deviceInfo.model } - function checkBattery() { - // We are fine if we are connected to the charger: - if (batteryMonitor.charging) { - return true; - } - - // If we have enough battery then we are fine: - if (!batteryMonitor.critical) { - return true; - } - - return false; + function checkDiskSpace() { + return fileSystem.hasFreeSpace(fileNaming.path) } ImageSettings { - id: imageSettings - camera: cam - function setImageResolution() { - if (!imageSettings.setResolution(settings.imageAspectRatio, settings.imageResolution)) { - showError(qsTr("Failed to set required resolution")); - } + id: imageSettings + camera: cam + function setImageResolution() { + if (!imageSettings.setResolution(settings.imageAspectRatio, settings.imageResolution)) { + showError(qsTr("Failed to set required resolution")) } + } - onReadyChanged: { - if (ready) { - imageSettings.setImageResolution(); - } + onReadyChanged: { + if (ready) { + imageSettings.setImageResolution() } + } } VideoSettings { - id: videoSettings - camera: cam + id: videoSettings + camera: cam - function setVideoResolution() { - if (!videoSettings.setResolution(settings.videoAspectRatio, settings.videoResolution)) { - showError(qsTr("Failed to set required resolution")); - } + function setVideoResolution() { + if (!videoSettings.setResolution(settings.videoAspectRatio, settings.videoResolution)) { + showError(qsTr("Failed to set required resolution")) } + } - onReadyChanged: { - if (ready) { - videoSettings.setVideoResolution(); - } + onReadyChanged: { + if (ready) { + videoSettings.setVideoResolution() } + } } Connections { - target: settings - - onImageAspectRatioChanged: { - imageSettings.setImageResolution(); - } - - onImageResolutionChanged: { - imageSettings.setImageResolution(); - } - - onVideoResolutionChanged: { - videoSettings.setVideoResolution(); - } - } - - Camera { - id: cam - anchors.fill: parent - - onRoiChanged: roi.normalize = false; - - GridLines { - x: cam.renderArea.x - y: cam.renderArea.y - width: cam.renderArea.width - height: cam.renderArea.height - visible: settings.gridEnabled - } - - FocusReticle { - id: focusReticle - cam: cam - visible: pageStack.currentPage && pageStack.currentPage.controlsVisible && pageStack.currentPage.focusReticleVisible && cam && cam.autoFocus.canFocus(cam.scene.value); - cafStatus: cam ? cam.autoFocus.cafStatus : -1 - status: cam ? cam.autoFocus.status : -1 - } - - onError: { - if (pipelineManager.error) { - // Ignore any subsequent errors. - // Killing pulseaudio while recording will lead to an - // infinite supply of errors which will break the UI - // if we show a banner for each. - return; - } - - pipelineManager.error = true; - pageStack.currentPage.cameraError(); - console.log("Camera error (" + code + "): " + message + " " + debug); - showError(qsTr("Camera error. Please restart the application.")); - - // We cannot stop camera here. Seems there is a race condition somewhere - // which leads to a freeze if we do so. - } - - onRunningChanged: { - if (!cam.running) { - mountProtector.unlock(); - } - } - - Component.onDestruction: cam.stop(); - - // We need to show viewfinder below pages. - z: -1 - - Rectangle { - property bool dimmed: false - id: camDimmer - z: 1 - anchors.fill: parent - opacity: dimmed ? 1.0 : 0.0 - color: "black" - Behavior on opacity { - PropertyAnimation { duration: 150 } - } - } + target: settings - notifications: Sounds { - id: sounds - mute: !settings.soundEnabled - } - - } - - Binding { - target: cam.flash - property: "value" - when: cam.mode == Camera.ImageMode - value: settings.imageFlashMode - } - - Binding { - target: settings - property: "imageFlashMode" - when: cam.mode == Camera.ImageMode - value: cam.flash.value - } + onImageAspectRatioChanged: { + imageSettings.setImageResolution() + } - Binding { - target: cam.scene - property: "value" - when: cam.mode == Camera.VideoMode - value: settings.videoSceneMode - } - - Binding { - target: cam.scene - property: "value" - when: cam.mode == Camera.ImageMode - value: settings.imageSceneMode - } - - Binding { - target: cam.evComp - property: "value" - when: cam.mode == Camera.ImageMode - value: settings.imageEvComp - } - - Binding { - target: cam.evComp - property: "value" - when: cam.mode == Camera.VideoMode - value: settings.videoEvComp - } + onImageResolutionChanged: { + imageSettings.setImageResolution() + } - Binding { - target: settings - property: "imageEvComp" - when: cam.mode == Camera.ImageMode - value: cam.evComp.value - } - - Binding { - target: settings - property: "videoEvComp" - when: cam.mode == Camera.VideoMode - value: cam.evComp.value - } - - Binding { - target: cam.whiteBalance - property: "value" - when: cam.mode == Camera.ImageMode - value: settings.imageWhiteBalance - } - - Binding { - target: cam.whiteBalance - property: "value" - when: cam.mode == Camera.VideoMode - value: settings.videoWhiteBalance - } - - Binding { - target: cam.colorTone - property: "value" - when: cam.mode == Camera.ImageMode - value: settings.imageColorFilter - } - - Binding { - target: cam.colorTone - property: "value" - when: cam.mode == Camera.VideoMode - value: settings.videoColorFilter - } - - Binding { - target: cam.iso - property: "value" - when: cam.mode == Camera.ImageMode - value: settings.imageIso - } - - Binding { - target: settings - property: "imageIso" - when: cam.mode == Camera.ImageMode - value: cam.iso.value - } - - Binding { - target: cam.videoMute - property: "enabled" - value: settings.videoMuted - } - - Binding { - target: cam.roi - property: "enabled" - value: settings.faceDetectionEnabled && !focusReticle.pressed && !focusReticle.touchMode && cam.mode == Camera.ImageMode - } - - - TrackerStore { - id: trackerStore - active: cam.running - manufacturer: deviceInfo.manufacturer - model: deviceInfo.model + onVideoResolutionChanged: { + videoSettings.setVideoResolution() + } } ModeController { - id: cameraMode - cam: cam - dimmer: root.dimmer - } - - Connections { - target: cam - onModeChanged: { - if (cam.mode == Camera.VideoMode) { - replacePage("VideoPage.qml"); - } - else { - replacePage("ImagePage.qml"); - } - } + id: cameraMode + cam: cam + dimmer: root.dimmer } - Standby { - policyLost: pipelineManager.state == "policyLost" - show: !pageStack.currentPage || (pageStack.currentPage.activationData.standbyVisible && pageStack.currentPage.status == PageStatus.Active && pipelineManager.showStandBy) + Rectangle { + property bool dimmed: false + id: camDimmer + z: 1 + anchors.fill: parent + opacity: dimmed ? 1.0 : 0.0 + color: "black" + Behavior on opacity { + PropertyAnimation { duration: 150 } + } } DeviceKeys { - id: keys - active: Qt.application.active && pipelineManager.scaleAcquired - repeat: !settings.zoomAsShutter + id: keys + active: Qt.application.active && pipelineManager.scaleAcquired + repeat: !settings.zoomAsShutter } + +// Standby { +// policyLost: pipelineManager.state == "policyLost" +// TODO: +// show: !pageStack.currentPage || (pageStack.currentPage.activationData.standbyVisible && pageStack.currentPage.status == PageStatus.Active && pipelineManager.showStandBy) +// } } diff --git a/qml/qml.qrc b/qml/qml.qrc index df70b39..83cfe5d 100644 --- a/qml/qml.qrc +++ b/qml/qml.qrc @@ -2,16 +2,16 @@ main.qml + SettingsView.qml + CameraView.qml + CameraOverlay.qml + ImageOverlay.qml + VideoOverlay.qml + RecordingDurationLabel.qml + PostCaptureView.qml PipelineManager.qml FocusReticle.qml - CameraPage.qml - ControlsActivationData.qml - Standby.qml - CameraSettings.qml - VideoPage.qml - ImagePage.qml ZoomSlider.qml - RecordingPage.qml ModeController.qml ModeButton.qml CaptureButton.qml @@ -19,30 +19,33 @@ CameraToolBar.qml CameraToolBar.js data.js + PreviewImage.qml + ImageSettings.qml + VideoSettings.qml + ImageResolutionSettings.qml + VideoResolutionSettings.qml + SectionHeader.qml + TextSwitch.qml + CameraSettings.qml + ZoomCaptureButton.qml + ZoomCaptureCancel.qml + PostCaptureItem.qml + + CameraPage.qml + Standby.qml FlashButton.qml ImageSceneButton.qml ImageEvCompButton.qml ImageWhiteBalanceButton.qml ImageColorFilterButton.qml ImageIsoButton.qml - PreviewImage.qml CheckButton.qml VideoTorchButton.qml - PostCaptureItem.qml - PostCapturePage.qml VideoSceneButton.qml VideoEvCompButton.qml VideoWhiteBalanceButton.qml VideoColorFilterButton.qml VideoMuteButton.qml VideoPlayerPage.qml - SectionHeader.qml - TextSwitch.qml - ImageSettingsDialog.qml - ImageResolutionSettings.qml - VideoSettingsDialog.qml - VideoResolutionSettings.qml - ZoomCaptureButton.qml - ZoomCaptureCancel.qml -- 2.25.1