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