Fixes for focus reticle
[harmattan/cameraplus] / qml / FocusReticle.qml
1 // -*- qml -*-
2
3 /*!
4  * This file is part of CameraPlus.
5  *
6  * Copyright (C) 2012 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: I've seen the reticle color changing to red while dragging it but failed to reproduce :(
28 // TODO: hide all controls when we are focusing
29 // TODO: hide all controls when we are dragging
30
31 MouseArea {
32         property int cafStatus: AutoFocus.None
33         property int status: AutoFocus.None
34         property Camera cam: null
35         id: mouse
36
37         // A 100x100 central "rectangle"
38         property variant centerRect: Qt.rect((mouse.width / 2 - 50), (mouse.height / 2) - 50, 100, 100);
39
40         property alias touchMode: reticle.touchMode
41
42         x: cam ? cam.renderArea.x : 0
43         y: cam ? cam.renderArea.y : 0
44         width: cam ? cam.renderArea.width : 0
45         height: cam ? cam.renderArea.height : 0
46
47         Connections {
48                 target: settings
49                 // Changing mode (which implies changing pages) will not reset ROI
50                 // thus we do it here
51                 onModeChanged: {
52                         moveToCenter();
53                         cam.autoFocus.setRegionOfInterest(Qt.rect(0, 0, 0, 0));
54                 }
55         }
56
57         Connections {
58                 target: cam
59                 onRunningChanged: {
60                         if (cam.running) {
61                                 setRegionOfInterest();
62                         }
63                 }
64         }
65 /*
66         // This is for debugging
67         Rectangle {
68                 color: "blue"
69                 opacity: 0.2
70                 anchors.fill: parent
71         }
72
73         Rectangle {
74                 color: "red"
75                 opacity: 0.4
76                 x: centerRect.x
77                 y: centerRect.y
78                 width: centerRect.width
79                 height: centerRect.height
80         }
81 */
82         drag.target: reticle
83         drag.axis: Drag.XandYAxis
84         drag.minimumX: 0 - (0.1 * reticle.width)
85         drag.minimumY: 0 - (0.1 * reticle.height)
86         drag.maximumX: width - reticle.width + (0.1 * reticle.width)
87         drag.maximumY: height - reticle.height + (0.1 * reticle.height)
88
89         onStatusChanged: {
90                 if (status != AutoFocus.Running) {
91                         reticle.visible = true;
92                 }
93         }
94
95         function predictColor(caf, status) {
96                 if (status == AutoFocus.Success) {
97                         return "steelblue";
98                 }
99                 else if (status == AutoFocus.Fail) {
100                         return "red";
101                 }
102                 else if (status == AutoFocus.Running) {
103                         return "white";
104                 }
105                 else if (caf == AutoFocus.Success) {
106                         return "steelblue";
107                 }
108                 else {
109                         return "white";
110                 }
111         }
112
113         function moveToCenter() {
114                 reticle.anchors.centerIn = reticle.parent;
115                 reticle.touchMode = false;
116         }
117
118         function moveReticle(x, y) {
119                 var xPos = x - ((reticle.width * 1) / 2);
120                 var yPos = y - ((reticle.height * 1) / 2);
121                 xPos = Math.min(Math.max(xPos, drag.minimumX), drag.maximumX);
122                 yPos = Math.min(Math.max(yPos, drag.minimumY), drag.maximumY);
123                 reticle.x = xPos;
124                 reticle.y = yPos;
125                 reticle.anchors.centerIn = undefined;
126                 reticle.touchMode = true;
127         }
128
129         function moveToCenterIfNeeded(x, y) {
130                 if (x >= centerRect.x && y >= centerRect.y &&
131                     x <= centerRect.x + centerRect.width &&
132                     y <= centerRect.y + centerRect.height) {
133                         moveToCenter();
134                 }
135                 else {
136                         reticle.anchors.centerIn = undefined;
137                         reticle.touchMode = true;
138                 }
139         }
140
141         function setRegionOfInterest() {
142                 if (!reticle.touchMode) {
143 //                        console.log("resetting ROI");
144                         cam.autoFocus.setRegionOfInterest(Qt.rect(0, 0, 0, 0));
145                         return;
146                 }
147
148                 // take into account scale:
149                 var x = reticle.x + (reticle.width * 0.1);
150                 var y = reticle.y + (reticle.height * 0.1);
151
152                 var width = reticle.width * 0.8;
153                 var height = reticle.height * 0.8;
154
155                 // in terms of video resolution:
156                 x = (cam.videoResolution.width * x) / mouse.width;
157                 width = (cam.videoResolution.width * width) / mouse.width;
158                 y = (cam.videoResolution.height * y) / mouse.height;
159                 height = (cam.videoResolution.height * height) / mouse.height;
160
161                 // Translate to normalized coordinates (1x1 square) as expected by our C++ backend
162                 x = x / cam.videoResolution.width;
163                 width = width / cam.videoResolution.width;
164                 y = y / cam.videoResolution.height;
165                 height = height / cam.videoResolution.height;
166
167 //                console.log("Setting ROI to: " + x + " " + y);
168                 cam.autoFocus.setRegionOfInterest(Qt.rect(x, y, width, height));
169         }
170
171         onReleased: {
172                 moveToCenterIfNeeded(mouse.x, mouse.y);
173                 setRegionOfInterest();
174         }
175
176         onPressed: {
177                 reticle.anchors.centerIn = undefined;
178                 moveReticle(mouse.x, mouse.y);
179         }
180
181         FocusRectangle {
182                 id: reticle
183                 property variant center: Qt.point((mouse.width - width) / 2, (mouse.height - height) / 2);
184                 property bool touchMode: false
185
186                 scale: mouse.pressed ? 0.6 : touchMode ? 0.8 : 1.0
187
188                 width: 250
189                 height: 150
190
191                 anchors.centerIn: parent
192
193                 color: predictColor(cafStatus, status);
194
195                 Behavior on x {
196                         PropertyAnimation { duration: 100; }
197                 }
198
199                 Behavior on y {
200                         PropertyAnimation { duration: 100; }
201                 }
202
203                 Behavior on scale {
204                         PropertyAnimation { duration: 100; }
205                 }
206         }
207
208         Timer {
209                 interval: 500
210                 running: status == AutoFocus.Running
211                 triggeredOnStart: true
212                 repeat: true
213                 onTriggered: reticle.visible = !reticle.visible
214         }
215 }