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