removed a blank line
[harmattan/cameraplus] / qml / FocusReticle.qml
1 // -*- qml -*-
2
3 /*!
4  * This file is part of CameraPlus.
5  *
6  * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 import QtQuick 2.0
24 import QtCamera 1.0
25 import CameraPlus 1.0
26
27 // TODO: hide all controls when we are focusing
28 // TODO: hide all controls when we are dragging
29
30 MouseArea {
31     id: mouse
32     x: renderArea.x
33     y: renderArea.y
34     width: renderArea.width
35     height: renderArea.height
36     drag.minimumX: 0
37     drag.minimumY: 0
38     drag.maximumX: width - reticle.width
39     drag.maximumY: height - reticle.height
40
41     property variant videoResolution
42     property variant renderArea
43
44     property bool locked: false
45
46     property int cafStatus: AutoFocus.None
47     property int status: AutoFocus.None
48     property Camera cam
49     property bool touchMode
50
51     property variant touchPoint: Qt.point(mouse.width / 2, mouse.height / 2)
52
53     // A 100x100 central "rectangle"
54     property variant centerRect: Qt.rect((mouse.width / 2 - 50), (mouse.height / 2) - 50, 100, 100)
55
56     // ROI:
57     property variant primaryRoiRect: Qt.rect(0, 0, 0, 0)
58     property variant roiRects
59     property variant allRoiRects
60     property bool roiMode: allRoiRects != null && allRoiRects.length > 0 && !touchMode && !pressed
61
62     enabled: !cam.quirks.hasQuirk(Quirks.NoTouchFocus)
63
64     property variant __initialPos
65     onPressed: {
66         if (mouse.x >= reticle.x &&
67             mouse.y >= reticle.y &&
68             mouse.x <= reticle.x + reticle.width &&
69             mouse.y <= reticle.y + reticle.height) {
70             locked = true
71         }
72
73         __initialPos = touchPoint
74         calculateTouchPoint(mouse.x, mouse.y)
75     }
76
77     onReleased: {
78         calculateTouchPoint(mouse.x, mouse.y)
79         locked = false
80     }
81
82     onPositionChanged: calculateTouchPoint(mouse.x, mouse.y)
83     onCanceled: {
84         calculateTouchPoint(__initialPos.x, __initialPos.y)
85         locked = false
86     }
87
88     function resetReticle() {
89         calculateTouchPoint(centerRect.x, centerRect.y)
90     }
91
92     function setRegionOfInterest() {
93         if (!cam) {
94             // console.log("Cannot set ROI without camera object")
95             return
96         } else if (mouse.pressed) {
97             // console.log("Will not set ROI while pressed")
98             return
99         } else if (!touchMode && !roiMode) {
100             // console.log("resetting ROI")
101             if (cam.roi) {
102                 cam.roi.resetRegionOfInterest()
103             }
104
105             return
106         }
107
108         // TODO: rework this and move to unnormalized coordinates
109         // in terms of video resolution:
110         var rx = (videoResolution.width * reticle.x) / mouse.width
111         var rwidth = (videoResolution.width * reticle.width) / mouse.width
112         var ry = (videoResolution.height * reticle.y) / mouse.height
113         var rheight = (videoResolution.height * reticle.height) / mouse.height
114
115         // Translate to normalized coordinates (1x1 square) as expected by our C++ backend
116         rx = rx / videoResolution.width
117         rwidth = rwidth / videoResolution.width
118         ry = ry / videoResolution.height
119         rheight = rheight / videoResolution.height
120
121         // console.log("Setting ROI to: " + rx + "x" + ry)
122         cam.roi.setRegionOfInterest(Qt.rect(rx, ry, rwidth, rheight))
123     }
124
125     function calculateTouchPoint(x, y) {
126         if (x >= centerRect.x && y >= centerRect.y &&
127             x <= centerRect.x + centerRect.width &&
128             y <= centerRect.y + centerRect.height) {
129                 touchMode = false
130                 touchPoint = Qt.point(mouse.width / 2, mouse.height / 2)
131                 return
132         }
133
134         touchMode = true
135         touchPoint = Qt.point(x, y)
136     }
137
138     function predictColor(caf, status) {
139         if (status == AutoFocus.Success) {
140             return "steelblue"
141         } else if (status == AutoFocus.Fail) {
142             return "red"
143         } else if (status == AutoFocus.Running) {
144             return "white"
145         } else if (caf == AutoFocus.Success) {
146             return "steelblue"
147         } else {
148             return "white"
149         }
150     }
151
152     Repeater {
153         anchors.fill: parent
154         model: roiMode ? roiRects : 0
155
156         delegate: Rectangle {
157             x: modelData.x
158             y: modelData.y
159             width: modelData.width
160             height: modelData.height
161             color: "transparent"
162             border.color: "gray"
163             border.width: 2
164         }
165     }
166
167     FocusRectangle {
168         id: reticle
169         width: mouse.pressed ? 150 : mouse.touchMode ? 200 : roiMode ? primaryRoiRect.width : 250
170         height: mouse.pressed ? 90 : mouse.touchMode ? 120 : roiMode ? primaryRoiRect.height : 150
171         x: Math.min(Math.max(mouse.touchPoint.x - (width / 2), drag.minimumX), drag.maximumX)
172         y: Math.min(Math.max(mouse.touchPoint.y - (height / 2), drag.minimumY), drag.maximumY)
173         color: predictColor(cafStatus, status)
174
175         onXChanged: setRegionOfInterest()
176         onYChanged: setRegionOfInterest()
177         /*
178         Behavior on x {
179             PropertyAnimation { duration: 100 }
180             enabled: !mouse.pressed
181         }
182
183         Behavior on y {
184             PropertyAnimation { duration: 100 }
185             enabled: !mouse.pressed
186         }
187         */
188         Behavior on width {
189             PropertyAnimation { duration: 100 }
190         }
191
192         Behavior on height {
193             PropertyAnimation { duration: 100 }
194         }
195
196     }
197
198     Connections {
199         target: settings
200         // Changing mode (which implies changing pages) will not reset ROI
201         // thus we do it here
202         onModeChanged: resetReticle()
203     }
204
205     Connections {
206         target: cam
207         onRunningChanged: resetReticle()
208         onVideoResolutionChanged: resetReticle()
209     }
210
211     Connections {
212         target: cam.roi
213         onRegionsChanged: {
214             allRoiRects = regions
215             primaryRoiRect = primary
216             roiRects = rest
217
218             if (regions.length == 0) {
219                 resetReticle()
220                 return
221             }
222
223             touchPoint = Qt.point(primary.x + (reticle.width / 2),
224                 primary.y + (reticle.height / 2))
225         }
226     }
227
228     /*
229     // This is for debugging
230     Rectangle {
231         color: "blue"
232         opacity: 0.2
233         anchors.fill: parent
234     }
235
236     Rectangle {
237         color: "red"
238         opacity: 0.4
239         x: centerRect.x
240         y: centerRect.y
241         width: centerRect.width
242         height: centerRect.height
243     }
244     */
245     Timer {
246         interval: 500
247         running: status == AutoFocus.Running
248         triggeredOnStart: true
249         repeat: true
250         onTriggered: reticle.visible = !reticle.visible
251         onRunningChanged: {
252             if (!running) {
253                 reticle.visible = true
254             }
255         }
256     }
257 }