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