summaryrefslogtreecommitdiffstats
path: root/gui/patternpassword.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gui/patternpassword.cpp')
-rw-r--r--gui/patternpassword.cpp313
1 files changed, 313 insertions, 0 deletions
diff --git a/gui/patternpassword.cpp b/gui/patternpassword.cpp
new file mode 100644
index 000000000..4fc781298
--- /dev/null
+++ b/gui/patternpassword.cpp
@@ -0,0 +1,313 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <string>
+
+extern "C" {
+#include "../twcommon.h"
+#include "../minuitwrp/minui.h"
+}
+
+#include "rapidxml.hpp"
+#include "objects.hpp"
+
+GUIPatternPassword::GUIPatternPassword(xml_node<>* node)
+ : GUIObject(node)
+{
+ xml_attribute<>* attr;
+ xml_node<>* child;
+
+ ResetActiveDots();
+ mTrackingTouch = false;
+ mNeedRender = true;
+
+ ConvertStrToColor("blue", &mDotColor);
+ ConvertStrToColor("white", &mActiveDotColor);
+ ConvertStrToColor("blue", &mLineColor);
+
+ mDotImage = mActiveDotImage = NULL;
+ mDotCircle = mActiveDotCircle = NULL;
+ mDotRadius = 50;
+ mLineWidth = 35;
+
+ mAction = NULL;
+ mUpdate = 0;
+
+ if (!node)
+ return;
+
+ LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH, &mPlacement);
+
+ mAction = new GUIAction(node);
+
+ child = FindNode(node, "dot");
+ if(child)
+ {
+ mDotColor = LoadAttrColor(child, "color", mDotColor);
+ mActiveDotColor = LoadAttrColor(child, "activecolor", mActiveDotColor);
+ mDotRadius = LoadAttrIntScaleX(child, "radius", mDotRadius);
+
+ mDotImage = LoadAttrImage(child, "image");
+ mActiveDotImage = LoadAttrImage(child, "activeimage");
+ }
+
+ child = FindNode(node, "line");
+ if(child)
+ {
+ mLineColor = LoadAttrColor(child, "color", mLineColor);
+ mLineWidth = LoadAttrIntScaleX(child, "width", mLineWidth);
+ }
+
+ child = FindNode(node, "data");
+ if(child)
+ mPassVar = LoadAttrString(child, "name", "");
+
+
+ if(!mDotImage || !mDotImage->GetResource() || !mActiveDotImage || !mActiveDotImage->GetResource())
+ {
+ mDotCircle = gr_render_circle(mDotRadius, mDotColor.red, mDotColor.green, mDotColor.blue, mDotColor.alpha);
+ mActiveDotCircle = gr_render_circle(mDotRadius/2, mActiveDotColor.red, mActiveDotColor.green, mActiveDotColor.blue, mActiveDotColor.alpha);
+ }
+ else
+ mDotRadius = mDotImage->GetWidth()/2;
+
+ SetRenderPos(mRenderX, mRenderY, mRenderW, mRenderH);
+}
+
+GUIPatternPassword::~GUIPatternPassword()
+{
+ delete mDotImage;
+ delete mActiveDotImage;
+ delete mAction;
+
+ if(mDotCircle)
+ gr_free_surface(mDotCircle);
+
+ if(mActiveDotCircle)
+ gr_free_surface(mActiveDotCircle);
+}
+
+void GUIPatternPassword::ResetActiveDots()
+{
+ mConnectedDotsLen = 0;
+ mCurLineX = mCurLineY = -1;
+ for(int i = 0; i < 9; ++i)
+ mDots[i].active = false;
+}
+
+int GUIPatternPassword::SetRenderPos(int x, int y, int w, int h)
+{
+ mRenderX = x;
+ mRenderY = y;
+
+ if (w || h)
+ {
+ mRenderW = w;
+ mRenderH = h;
+
+ mAction->SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
+ SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
+ }
+
+ CalculateDotPositions();
+ return 0;
+}
+
+void GUIPatternPassword::CalculateDotPositions(void)
+{
+ const int step_x = (mRenderW - mDotRadius*2) / 2;
+ const int step_y = (mRenderH - mDotRadius*2) / 2;
+ int x = mRenderX;
+ int y = mRenderY;
+
+ for(int r = 0; r < 3; ++r)
+ {
+ for(int c = 0; c < 3; ++c)
+ {
+ mDots[3*r+c].x = x;
+ mDots[3*r+c].y = y;
+ x += step_x;
+ }
+ x = mRenderX;
+ y += step_y;
+ }
+}
+
+int GUIPatternPassword::Render(void)
+{
+ if(!isConditionTrue())
+ return 0;
+
+ gr_color(mLineColor.red, mLineColor.green, mLineColor.blue, mLineColor.alpha);
+ for(size_t i = 1; i < mConnectedDotsLen; ++i) {
+ const Dot& dp = mDots[mConnectedDots[i-1]];
+ const Dot& dc = mDots[mConnectedDots[i]];
+ gr_line(dp.x + mDotRadius, dp.y + mDotRadius, dc.x + mDotRadius, dc.y + mDotRadius, mLineWidth);
+ }
+
+ if(mConnectedDotsLen > 0 && mTrackingTouch) {
+ const Dot& dc = mDots[mConnectedDots[mConnectedDotsLen-1]];
+ gr_line(dc.x + mDotRadius, dc.y + mDotRadius, mCurLineX, mCurLineY, mLineWidth);
+ }
+
+ for(int i = 0; i < 9; ++i) {
+ if(mDotCircle) {
+ gr_blit(mDotCircle, 0, 0, gr_get_width(mDotCircle), gr_get_height(mDotCircle), mDots[i].x, mDots[i].y);
+ if(mDots[i].active) {
+ gr_blit(mActiveDotCircle, 0, 0, gr_get_width(mActiveDotCircle), gr_get_height(mActiveDotCircle), mDots[i].x + mDotRadius/2, mDots[i].y + mDotRadius/2);
+ }
+ } else {
+ if(mDots[i].active) {
+ gr_blit(mActiveDotImage->GetResource(), 0, 0, mActiveDotImage->GetWidth(), mActiveDotImage->GetHeight(),
+ mDots[i].x + (mDotRadius - mActiveDotImage->GetWidth()/2), mDots[i].y + (mDotRadius - mActiveDotImage->GetHeight()/2));
+ } else {
+ gr_blit(mDotImage->GetResource(), 0, 0, mDotImage->GetWidth(), mDotImage->GetHeight(), mDots[i].x, mDots[i].y);
+ }
+ }
+ }
+ return 0;
+}
+
+int GUIPatternPassword::Update(void)
+{
+ if(!isConditionTrue())
+ return 0;
+
+ int res = mNeedRender ? 2 : 1;
+ mNeedRender = false;
+ return res;
+}
+
+bool GUIPatternPassword::IsInRect(int x, int y, int rx, int ry, int rw, int rh)
+{
+ return x >= rx && y >= ry && x <= rx+rw && y <= ry+rh;
+}
+
+int GUIPatternPassword::InDot(int x, int y)
+{
+ for(int i = 0; i < 9; ++i) {
+ if(IsInRect(x, y, mDots[i].x - mDotRadius*1.5, mDots[i].y - mDotRadius*1.5, mDotRadius*6, mDotRadius*6))
+ return i;
+ }
+ return -1;
+}
+
+bool GUIPatternPassword::DotUsed(int dot_idx)
+{
+ for(size_t i = 0; i < mConnectedDotsLen; ++i) {
+ if(mConnectedDots[i] == dot_idx)
+ return true;
+ }
+ return false;
+}
+
+void GUIPatternPassword::ConnectDot(int dot_idx)
+{
+ if(mConnectedDotsLen >= 9)
+ {
+ LOGERR("mConnectedDots in GUIPatternPassword has overflown!\n");
+ return;
+ }
+
+ mConnectedDots[mConnectedDotsLen++] = dot_idx;
+ mDots[dot_idx].active = true;
+}
+
+void GUIPatternPassword::ConnectIntermediateDots(int dot_idx)
+{
+ if(mConnectedDotsLen == 0)
+ return;
+
+ const int last_dot = mConnectedDots[mConnectedDotsLen-1];
+
+ // The line is vertical and has crossed a point in the middle
+ if(dot_idx%3 == last_dot%3 && abs(dot_idx - last_dot) > 3)
+ ConnectDot(3 + dot_idx%3);
+ // the line is horizontal and has crossed a point in the middle
+ else if(dot_idx/3 == last_dot/3 && abs(dot_idx - last_dot) > 1)
+ ConnectDot((dot_idx/3)*3 + 1);
+ // the line is diagonal and has crossed the middle point
+ else if((dot_idx == 0 && last_dot == 8) || (dot_idx == 8 && last_dot == 0) ||
+ (dot_idx == 2 && last_dot == 6) || (dot_idx == 6 && last_dot == 2))
+ {
+ ConnectDot(4);
+ }
+}
+
+int GUIPatternPassword::NotifyTouch(TOUCH_STATE state, int x, int y)
+{
+ if(!isConditionTrue())
+ return -1;
+
+ switch (state)
+ {
+ case TOUCH_START:
+ {
+ const int dot_idx = InDot(x, y);
+ if(dot_idx == -1)
+ break;
+
+ mTrackingTouch = true;
+ ResetActiveDots();
+ ConnectDot(dot_idx);
+ DataManager::Vibrate("tw_button_vibrate");
+ mCurLineX = x;
+ mCurLineY = y;
+ mNeedRender = true;
+ break;
+ }
+ case TOUCH_DRAG:
+ {
+ if(!mTrackingTouch)
+ break;
+
+ const int dot_idx = InDot(x, y);
+ if(dot_idx != -1 && !DotUsed(dot_idx))
+ {
+ ConnectIntermediateDots(dot_idx);
+ ConnectDot(dot_idx);
+ DataManager::Vibrate("tw_button_vibrate");
+ }
+
+ mCurLineX = x;
+ mCurLineY = y;
+ mNeedRender = true;
+ break;
+ }
+ case TOUCH_RELEASE:
+ {
+ if(!mTrackingTouch)
+ break;
+
+ mNeedRender = true;
+ mTrackingTouch = false;
+ PatternDrawn();
+ ResetActiveDots();
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+void GUIPatternPassword::PatternDrawn()
+{
+ if(!mPassVar.empty() && mConnectedDotsLen > 0)
+ {
+ std::string pass;
+ for(size_t i = 0; i < mConnectedDotsLen; ++i)
+ pass += '1' + mConnectedDots[i];
+ DataManager::SetValue(mPassVar, pass);
+ }
+
+ if(mAction)
+ mAction->doActions();
+}