blob: ed152851fa49e1ed0574cf66f7dc9600e1189e0e [file] [log] [blame]
Vojtech Bocek7e11ac52015-03-05 23:21:49 +01001#include <stdarg.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <sys/types.h>
7#include <time.h>
8#include <unistd.h>
9#include <stdlib.h>
10
11#include <string>
12
13extern "C" {
14#include "../twcommon.h"
15#include "../minuitwrp/minui.h"
16}
17
18#include "rapidxml.hpp"
19#include "objects.hpp"
20
21GUIPatternPassword::GUIPatternPassword(xml_node<>* node)
22 : GUIObject(node)
23{
24 xml_attribute<>* attr;
25 xml_node<>* child;
26
27 ResetActiveDots();
28 mTrackingTouch = false;
29 mNeedRender = true;
30
31 ConvertStrToColor("blue", &mDotColor);
32 ConvertStrToColor("white", &mActiveDotColor);
33 ConvertStrToColor("blue", &mLineColor);
34
35 mDotImage = mActiveDotImage = NULL;
36 mDotCircle = mActiveDotCircle = NULL;
37 mDotRadius = 50;
38 mLineWidth = 35;
39
40 mAction = NULL;
41 mUpdate = 0;
42
43 if (!node)
44 return;
45
46 LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH, &mPlacement);
47
48 mAction = new GUIAction(node);
49
50 child = FindNode(node, "dot");
51 if(child)
52 {
53 mDotColor = LoadAttrColor(child, "color", mDotColor);
54 mActiveDotColor = LoadAttrColor(child, "activecolor", mActiveDotColor);
55 mDotRadius = LoadAttrIntScaleX(child, "radius", mDotRadius);
56
57 mDotImage = LoadAttrImage(child, "image");
58 mActiveDotImage = LoadAttrImage(child, "activeimage");
59 }
60
61 child = FindNode(node, "line");
62 if(child)
63 {
64 mLineColor = LoadAttrColor(child, "color", mLineColor);
65 mLineWidth = LoadAttrIntScaleX(child, "width", mLineWidth);
66 }
67
68 child = FindNode(node, "data");
69 if(child)
70 mPassVar = LoadAttrString(child, "name", "");
71
72
73 if(!mDotImage || !mDotImage->GetResource() || !mActiveDotImage || !mActiveDotImage->GetResource())
74 {
75 mDotCircle = gr_render_circle(mDotRadius, mDotColor.red, mDotColor.green, mDotColor.blue, mDotColor.alpha);
76 mActiveDotCircle = gr_render_circle(mDotRadius/2, mActiveDotColor.red, mActiveDotColor.green, mActiveDotColor.blue, mActiveDotColor.alpha);
77 }
78 else
79 mDotRadius = mDotImage->GetWidth()/2;
80
81 SetRenderPos(mRenderX, mRenderY, mRenderW, mRenderH);
82}
83
84GUIPatternPassword::~GUIPatternPassword()
85{
86 delete mDotImage;
87 delete mActiveDotImage;
88 delete mAction;
89
90 if(mDotCircle)
91 gr_free_surface(mDotCircle);
92
93 if(mActiveDotCircle)
94 gr_free_surface(mActiveDotCircle);
95}
96
97void GUIPatternPassword::ResetActiveDots()
98{
99 mConnectedDotsLen = 0;
100 mCurLineX = mCurLineY = -1;
101 for(int i = 0; i < 9; ++i)
102 mDots[i].active = false;
103}
104
105int GUIPatternPassword::SetRenderPos(int x, int y, int w, int h)
106{
107 mRenderX = x;
108 mRenderY = y;
109
110 if (w || h)
111 {
112 mRenderW = w;
113 mRenderH = h;
114
115 mAction->SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
116 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
117 }
118
119 CalculateDotPositions();
120 return 0;
121}
122
123void GUIPatternPassword::CalculateDotPositions(void)
124{
125 const int step_x = (mRenderW - mDotRadius*2) / 2;
126 const int step_y = (mRenderH - mDotRadius*2) / 2;
127 int x = mRenderX;
128 int y = mRenderY;
129
130 for(int r = 0; r < 3; ++r)
131 {
132 for(int c = 0; c < 3; ++c)
133 {
134 mDots[3*r+c].x = x;
135 mDots[3*r+c].y = y;
136 x += step_x;
137 }
138 x = mRenderX;
139 y += step_y;
140 }
141}
142
143int GUIPatternPassword::Render(void)
144{
145 if(!isConditionTrue())
146 return 0;
147
148 gr_color(mLineColor.red, mLineColor.green, mLineColor.blue, mLineColor.alpha);
149 for(size_t i = 1; i < mConnectedDotsLen; ++i) {
150 const Dot& dp = mDots[mConnectedDots[i-1]];
151 const Dot& dc = mDots[mConnectedDots[i]];
152 gr_line(dp.x + mDotRadius, dp.y + mDotRadius, dc.x + mDotRadius, dc.y + mDotRadius, mLineWidth);
153 }
154
155 if(mConnectedDotsLen > 0 && mTrackingTouch) {
156 const Dot& dc = mDots[mConnectedDots[mConnectedDotsLen-1]];
157 gr_line(dc.x + mDotRadius, dc.y + mDotRadius, mCurLineX, mCurLineY, mLineWidth);
158 }
159
160 for(int i = 0; i < 9; ++i) {
161 if(mDotCircle) {
162 gr_blit(mDotCircle, 0, 0, gr_get_width(mDotCircle), gr_get_height(mDotCircle), mDots[i].x, mDots[i].y);
163 if(mDots[i].active) {
164 gr_blit(mActiveDotCircle, 0, 0, gr_get_width(mActiveDotCircle), gr_get_height(mActiveDotCircle), mDots[i].x + mDotRadius/2, mDots[i].y + mDotRadius/2);
165 }
166 } else {
167 if(mDots[i].active) {
168 gr_blit(mActiveDotImage->GetResource(), 0, 0, mActiveDotImage->GetWidth(), mActiveDotImage->GetHeight(),
169 mDots[i].x + (mDotRadius - mActiveDotImage->GetWidth()/2), mDots[i].y + (mDotRadius - mActiveDotImage->GetHeight()/2));
170 } else {
171 gr_blit(mDotImage->GetResource(), 0, 0, mDotImage->GetWidth(), mDotImage->GetHeight(), mDots[i].x, mDots[i].y);
172 }
173 }
174 }
175 return 0;
176}
177
178int GUIPatternPassword::Update(void)
179{
180 if(!isConditionTrue())
181 return 0;
182
183 int res = mNeedRender ? 2 : 1;
184 mNeedRender = false;
185 return res;
186}
187
188bool GUIPatternPassword::IsInRect(int x, int y, int rx, int ry, int rw, int rh)
189{
190 return x >= rx && y >= ry && x <= rx+rw && y <= ry+rh;
191}
192
193int GUIPatternPassword::InDot(int x, int y)
194{
195 for(int i = 0; i < 9; ++i) {
196 if(IsInRect(x, y, mDots[i].x - mDotRadius*1.5, mDots[i].y - mDotRadius*1.5, mDotRadius*6, mDotRadius*6))
197 return i;
198 }
199 return -1;
200}
201
202bool GUIPatternPassword::DotUsed(int dot_idx)
203{
204 for(size_t i = 0; i < mConnectedDotsLen; ++i) {
205 if(mConnectedDots[i] == dot_idx)
206 return true;
207 }
208 return false;
209}
210
211void GUIPatternPassword::ConnectDot(int dot_idx)
212{
213 if(mConnectedDotsLen >= 9)
214 {
215 LOGERR("mConnectedDots in GUIPatternPassword has overflown!\n");
216 return;
217 }
218
219 mConnectedDots[mConnectedDotsLen++] = dot_idx;
220 mDots[dot_idx].active = true;
221}
222
223void GUIPatternPassword::ConnectIntermediateDots(int dot_idx)
224{
225 if(mConnectedDotsLen == 0)
226 return;
227
228 const int last_dot = mConnectedDots[mConnectedDotsLen-1];
Vojtech Boceke8c39272015-03-15 15:25:37 +0100229 int mid = -1;
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100230
231 // The line is vertical and has crossed a point in the middle
Vojtech Boceke8c39272015-03-15 15:25:37 +0100232 if(dot_idx%3 == last_dot%3 && abs(dot_idx - last_dot) > 3) {
233 mid = 3 + dot_idx%3;
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100234 // the line is horizontal and has crossed a point in the middle
Vojtech Boceke8c39272015-03-15 15:25:37 +0100235 } else if(dot_idx/3 == last_dot/3 && abs(dot_idx - last_dot) > 1) {
236 mid = (dot_idx/3)*3 + 1;
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100237 // the line is diagonal and has crossed the middle point
Vojtech Boceke8c39272015-03-15 15:25:37 +0100238 } else if((dot_idx == 0 && last_dot == 8) || (dot_idx == 8 && last_dot == 0) ||
239 (dot_idx == 2 && last_dot == 6) || (dot_idx == 6 && last_dot == 2)) {
240 mid = 4;
241 } else {
242 return;
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100243 }
Vojtech Boceke8c39272015-03-15 15:25:37 +0100244
245 if(!DotUsed(mid))
246 ConnectDot(mid);
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100247}
248
249int GUIPatternPassword::NotifyTouch(TOUCH_STATE state, int x, int y)
250{
251 if(!isConditionTrue())
252 return -1;
253
254 switch (state)
255 {
256 case TOUCH_START:
257 {
258 const int dot_idx = InDot(x, y);
259 if(dot_idx == -1)
260 break;
261
262 mTrackingTouch = true;
263 ResetActiveDots();
264 ConnectDot(dot_idx);
265 DataManager::Vibrate("tw_button_vibrate");
266 mCurLineX = x;
267 mCurLineY = y;
268 mNeedRender = true;
269 break;
270 }
271 case TOUCH_DRAG:
272 {
273 if(!mTrackingTouch)
274 break;
275
276 const int dot_idx = InDot(x, y);
277 if(dot_idx != -1 && !DotUsed(dot_idx))
278 {
279 ConnectIntermediateDots(dot_idx);
280 ConnectDot(dot_idx);
281 DataManager::Vibrate("tw_button_vibrate");
282 }
283
284 mCurLineX = x;
285 mCurLineY = y;
286 mNeedRender = true;
287 break;
288 }
289 case TOUCH_RELEASE:
290 {
291 if(!mTrackingTouch)
292 break;
293
294 mNeedRender = true;
295 mTrackingTouch = false;
296 PatternDrawn();
297 ResetActiveDots();
298 break;
299 }
300 default:
301 break;
302 }
303 return 0;
304}
305
306void GUIPatternPassword::PatternDrawn()
307{
308 if(!mPassVar.empty() && mConnectedDotsLen > 0)
309 {
310 std::string pass;
311 for(size_t i = 0; i < mConnectedDotsLen; ++i)
312 pass += '1' + mConnectedDots[i];
313 DataManager::SetValue(mPassVar, pass);
314 }
315
316 if(mAction)
317 mAction->doActions();
318}