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