Reset touch focus back if the user starts dragging the view (onCanceled)
[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 1.1
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: cam ? cam.renderArea.x : 0
33     y: cam ? cam.renderArea.y : 0
34     width: cam ? cam.renderArea.width : 0
35     height: cam ? cam.renderArea.height : 0
36     drag.minimumX: 0
37     drag.minimumY: 0
38     drag.maximumX: width - reticle.width
39     drag.maximumY: height - reticle.height
40
41     property int cafStatus: AutoFocus.None
42     property int status: AutoFocus.None
43     property Camera cam
44     property bool touchMode
45
46     property variant touchPoint: Qt.point(mouse.width / 2, mouse.height / 2)
47
48     // A 100x100 central "rectangle"
49     property variant centerRect: Qt.rect((mouse.width / 2 - 50), (mouse.height / 2) - 50, 100, 100)
50
51     // ROI:
52     property variant primaryRoiRect: Qt.rect(0, 0, 0, 0)
53     property variant roiRects
54     property variant allRoiRects
55     property bool roiMode: allRoiRects != null && allRoiRects.length > 0 && !touchMode && !pressed
56
57     property variant __initialPos
58     onPressed: {
59         __initialPos = touchPoint
60         calculateTouchPoint(mouse.x, mouse.y)
61     }
62
63     onReleased: calculateTouchPoint(mouse.x, mouse.y)
64     onPositionChanged: calculateTouchPoint(mouse.x, mouse.y)
65     onCanceled: calculateTouchPoint(__initialPos.x, __initialPos.y)
66
67     function resetReticle() {
68         calculateTouchPoint(centerRect.x, centerRect.y)
69     }
70
71     function setRegionOfInterest() {
72         if (!cam) {
73             // console.log("Cannot set ROI without camera object")
74             return
75         } else if (mouse.pressed) {
76             // console.log("Will not set ROI while pressed")
77             return
78         } else if (!touchMode && !roiMode) {
79             // console.log("resetting ROI")
80             cam.roi.resetRegionOfInterest()
81             return
82         }
83
84         // TODO: rework this and move to unnormalized coordinates
85         // in terms of video resolution:
86         var rx = (cam.videoResolution.width * reticle.x) / mouse.width
87         var rwidth = (cam.videoResolution.width * reticle.width) / mouse.width
88         var ry = (cam.videoResolution.height * reticle.y) / mouse.height
89         var rheight = (cam.videoResolution.height * reticle.height) / mouse.height
90
91         // Translate to normalized coordinates (1x1 square) as expected by our C++ backend
92         rx = rx / cam.videoResolution.width
93         rwidth = rwidth / cam.videoResolution.width
94         ry = ry / cam.videoResolution.height
95         rheight = rheight / cam.videoResolution.height
96
97         // console.log("Setting ROI to: " + rx + "x" + ry)
98         cam.roi.setRegionOfInterest(Qt.rect(rx, ry, rwidth, rheight))
99     }
100
101     function calculateTouchPoint(x, y) {
102         if (x >= centerRect.x && y >= centerRect.y &&
103             x <= centerRect.x + centerRect.width &&
104             y <= centerRect.y + centerRect.height) {
105                 touchMode = false
106                 touchPoint = Qt.point(mouse.width / 2, mouse.height / 2)
107                 return
108         }
109
110         touchMode = true
111         touchPoint = Qt.point(x, y)
112     }
113
114     function predictColor(caf, status) {
115         if (status == AutoFocus.Success) {
116             return "steelblue"
117         } else if (status == AutoFocus.Fail) {
118             return "red"
119         } else if (status == AutoFocus.Running) {
120             return "white"
121         } else if (caf == AutoFocus.Success) {
122             return "steelblue"
123         } else {
124             return "white"
125         }
126     }
127
128     Repeater {
129         anchors.fill: parent
130         model: roiMode ? roiRects : 0
131
132         delegate: Rectangle {
133             x: modelData.x
134             y: modelData.y
135             width: modelData.width
136             height: modelData.height
137             color: "transparent"
138             border.color: "gray"
139             border.width: 2
140         }
141     }
142
143     FocusRectangle {
144         id: reticle
145         width: mouse.pressed ? 150 : mouse.touchMode ? 200 : roiMode ? primaryRoiRect.width : 250
146         height: mouse.pressed ? 90 : mouse.touchMode ? 120 : roiMode ? primaryRoiRect.height : 150
147         x: Math.min(Math.max(mouse.touchPoint.x - (width / 2), drag.minimumX), drag.maximumX)
148         y: Math.min(Math.max(mouse.touchPoint.y - (height / 2), drag.minimumY), drag.maximumY)
149         color: predictColor(cafStatus, status)
150
151         onXChanged: setRegionOfInterest()
152         onYChanged: setRegionOfInterest()
153         /*
154         Behavior on x {
155             PropertyAnimation { duration: 100 }
156             enabled: !mouse.pressed
157         }
158
159         Behavior on y {
160             PropertyAnimation { duration: 100 }
161             enabled: !mouse.pressed
162         }
163         */
164         Behavior on width {
165             PropertyAnimation { duration: 100 }
166         }
167
168         Behavior on height {
169             PropertyAnimation { duration: 100 }
170         }
171
172     }
173
174     Connections {
175         target: settings
176         // Changing mode (which implies changing pages) will not reset ROI
177         // thus we do it here
178         onModeChanged: resetReticle()
179     }
180
181     Connections {
182         target: cam
183         onRunningChanged: resetReticle()
184         onVideoResolutionChanged: resetReticle()
185     }
186
187     Connections {
188         target: cam.roi
189         onRegionsChanged: {
190             allRoiRects = regions
191             primaryRoiRect = primary
192             roiRects = rest
193
194             if (regions.length == 0) {
195                 resetReticle()
196                 return
197             }
198
199             touchPoint = Qt.point(primary.x + (reticle.width / 2),
200                 primary.y + (reticle.height / 2))
201         }
202     }
203
204     /*
205     // This is for debugging
206     Rectangle {
207         color: "blue"
208         opacity: 0.2
209         anchors.fill: parent
210     }
211
212     Rectangle {
213         color: "red"
214         opacity: 0.4
215         x: centerRect.x
216         y: centerRect.y
217         width: centerRect.width
218         height: centerRect.height
219     }
220     */
221     Timer {
222         interval: 500
223         running: status == AutoFocus.Running
224         triggeredOnStart: true
225         repeat: true
226         onTriggered: reticle.visible = !reticle.visible
227         onRunningChanged: {
228             if (!running) {
229                 reticle.visible = true
230             }
231         }
232     }
233 }