#include #include #include #include #include #include #include #include #include #include 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]; int mid = -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) { mid = 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) { mid = (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)) { mid = 4; } else { return; } if(!DotUsed(mid)) ConnectDot(mid); } 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(); }