PatternCodeLock.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. #include "PatternCodeLock.h"
  2. #include <QPainter>
  3. #include <QPainterPath>
  4. #include <QPaintEvent>
  5. PatternCodeLockWidget::PatternCodeLockWidget(int numberOfEachRowAndCol, QWidget *parent)
  6. : QWidget(parent), numberOfEachRowAndCol(numberOfEachRowAndCol)
  7. {
  8. setMouseTracking(true);
  9. setMinimumSize(400, 400);
  10. for (int i = 0; i < numberOfEachRowAndCol; ++i) {
  11. for (int j = 0; j < numberOfEachRowAndCol; ++j) {
  12. circularStateList << CircularState::normal;
  13. smartCircularRectList << QRect();
  14. }
  15. }
  16. connect(&hoverTimer, &QTimer::timeout, this, &PatternCodeLockWidget::onHoverTimer);
  17. hoverTimer.setInterval(40);
  18. }
  19. PatternCodeLockWidget::~PatternCodeLockWidget() { }
  20. void PatternCodeLockWidget::paintEvent(QPaintEvent *event)
  21. {
  22. QPainter painter(this);
  23. painter.setRenderHint(QPainter::Antialiasing, true);
  24. const auto rect = event->rect();
  25. painter.fillRect(rect, QColor("#1D1D1D"));
  26. auto width = rect.width();
  27. auto height = rect.height();
  28. auto sideLength = std::min(width, height) - 20;
  29. auto halfSideLength = sideLength / 2;
  30. QRect drawZoneRect = QRect(-halfSideLength, -halfSideLength, sideLength, sideLength);
  31. drawZoneRect.translate(rect.center());
  32. painter.save();
  33. painter.setPen(QPen(QBrush("#141414"), 5));
  34. painter.drawRoundedRect(drawZoneRect, 12, 12);
  35. painter.restore();
  36. radiu = sideLength / (1 + 1 + numberOfEachRowAndCol * 2 + (numberOfEachRowAndCol - 1) * 3);
  37. bool mustUpdateCircularRect = isUpdateSmartCircularRect;
  38. for (int i = 0, listIndex = 0; i < numberOfEachRowAndCol; ++i) {
  39. for (int j = 0; j < numberOfEachRowAndCol; ++j, ++listIndex) {
  40. QPoint circularCenter =
  41. drawZoneRect.topLeft() + QPoint(2 * radiu + i * 5 * radiu, 2 * radiu + j * 5 * radiu);
  42. if (setList.contains(listIndex)) {
  43. if (PatternCodeLockSetUpState == PatternCodeLockState::setting
  44. || PatternCodeLockSetUpState == PatternCodeLockState::setted_valid) {
  45. painter.setPen(QPen(QBrush(QColor("#00FF80")), 3));
  46. } else {
  47. painter.setPen(QPen(QBrush(QColor("#FE4C40")), 3));
  48. }
  49. } else {
  50. painter.setPen(QPen(QBrush(Qt::white), 3));
  51. }
  52. if (listIndex == lastHoverIndex && hoverTimer.isActive()
  53. && PatternCodeLockSetUpState == PatternCodeLockState::setting) {
  54. painter.drawEllipse(circularCenter, radiu + currentchangeLength, radiu + currentchangeLength);
  55. } else {
  56. painter.drawEllipse(circularCenter, radiu, radiu);
  57. }
  58. if (mustUpdateCircularRect) {
  59. QRect newCircularRect = QRect(-radiu / 2, -radiu / 2, radiu, radiu);
  60. newCircularRect.translate(circularCenter);
  61. smartCircularRectList[listIndex] = newCircularRect;
  62. }
  63. painter.save();
  64. switch (circularStateList.at(listIndex)) {
  65. case CircularState::normal: {
  66. if (listIndex == lastHoverIndex && hoverTimer.isActive()
  67. && PatternCodeLockSetUpState == PatternCodeLockState::notSet) {
  68. painter.setBrush(Qt::white);
  69. painter.setPen(Qt::transparent);
  70. painter.drawEllipse(circularCenter, static_cast<int>(radiu * 0.5 + currentchangeLength),
  71. static_cast<int>(radiu * 0.5 + currentchangeLength));
  72. } else {
  73. painter.setBrush(QColor("#888888"));
  74. painter.setPen(Qt::transparent);
  75. painter.drawEllipse(circularCenter, radiu / 2, radiu / 2);
  76. }
  77. } break;
  78. case CircularState::hoverOnInnerSamrtCircular: {
  79. painter.setPen(Qt::transparent);
  80. if (PatternCodeLockSetUpState == PatternCodeLockState::notSet) {
  81. painter.setBrush(Qt::white);
  82. if (hoverTimer.isActive()) {
  83. painter.drawEllipse(circularCenter, static_cast<int>(radiu * 0.5 + currentchangeLength),
  84. static_cast<int>(radiu * 0.5 + currentchangeLength));
  85. } else {
  86. painter.drawEllipse(circularCenter, static_cast<int>(radiu * 0.7),
  87. static_cast<int>(radiu * 0.7));
  88. }
  89. } else {
  90. if (PatternCodeLockSetUpState == PatternCodeLockState::setting
  91. || PatternCodeLockSetUpState == PatternCodeLockState::setted_valid) {
  92. painter.setBrush(QColor("#00FF80"));
  93. } else {
  94. painter.setBrush(QColor("#FE4C40"));
  95. }
  96. painter.drawEllipse(circularCenter, static_cast<int>(radiu * 0.7), static_cast<int>(radiu * 0.7));
  97. }
  98. } break;
  99. }
  100. painter.restore();
  101. }
  102. }
  103. if (PatternCodeLockSetUpState != PatternCodeLockState::notSet) {
  104. painter.setBrush(Qt::transparent);
  105. if (PatternCodeLockSetUpState == PatternCodeLockState::setted_invalid) {
  106. painter.setPen(QPen(QBrush(QColor("#FE4C40")), 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
  107. } else {
  108. painter.setPen(QPen(QBrush(QColor("#00FF80")), 7, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
  109. }
  110. int setListSize = setList.size();
  111. for (int i = 0; i < setListSize; ++i) {
  112. if (i < (setListSize - 1)) {
  113. painter.drawLine(smartCircularRectList.at(setList.at(i)).center(),
  114. smartCircularRectList.at(setList.at(i + 1)).center());
  115. }
  116. }
  117. if (PatternCodeLockSetUpState == PatternCodeLockState::setting) {
  118. painter.drawLine(smartCircularRectList.at(setList.last()).center(), settingMousPos);
  119. }
  120. }
  121. if (mustUpdateCircularRect)
  122. isUpdateSmartCircularRect = false;
  123. }
  124. void PatternCodeLockWidget::resizeEvent(QResizeEvent *event)
  125. {
  126. isUpdateSmartCircularRect = true;
  127. QWidget::resizeEvent(event);
  128. }
  129. void PatternCodeLockWidget::mouseMoveEvent(QMouseEvent *event)
  130. {
  131. auto pos = event->pos();
  132. int currentHoverIndex = -1;
  133. if (PatternCodeLockSetUpState == PatternCodeLockState::notSet) {
  134. bool mouseInSomeSmartCircular { false };
  135. for (int i = 0; i < smartCircularRectList.size(); ++i) {
  136. if (smartCircularRectList.at(i).contains(pos)) {
  137. circularStateList[i] = CircularState::hoverOnInnerSamrtCircular;
  138. currentHoverIndex = i;
  139. mouseInSomeSmartCircular = true;
  140. } else {
  141. circularStateList[i] = CircularState::normal;
  142. }
  143. }
  144. if (mouseInSomeSmartCircular) {
  145. lastHoverIndex = currentHoverIndex;
  146. setCursor(Qt::PointingHandCursor);
  147. } else {
  148. setCursor(Qt::ArrowCursor);
  149. }
  150. if (!hoverTimer.isActive()) {
  151. if (this->mouseInSomeSmartCircular != mouseInSomeSmartCircular) //鼠标进入了某个小圆或从小圆出来
  152. {
  153. this->mouseInSomeSmartCircular = mouseInSomeSmartCircular;
  154. if (this->mouseInSomeSmartCircular) {
  155. currentchangeLength = 0;
  156. } else {
  157. currentchangeLength = radiu * 0.2;
  158. }
  159. hoverTimer.start();
  160. }
  161. }
  162. } else if (PatternCodeLockSetUpState == PatternCodeLockState::setting) {
  163. bool mouseInSomeSmartCircular { false };
  164. for (int i = 0; i < smartCircularRectList.size(); ++i) {
  165. if (smartCircularRectList.at(i).contains(pos)) {
  166. if (!setList.contains(i)) {
  167. setList << i;
  168. circularStateList[i] = CircularState::hoverOnInnerSamrtCircular;
  169. currentHoverIndex = i;
  170. }
  171. mouseInSomeSmartCircular = true;
  172. }
  173. }
  174. if (this->mouseInSomeSmartCircular != mouseInSomeSmartCircular) {
  175. this->mouseInSomeSmartCircular = mouseInSomeSmartCircular;
  176. if (mouseInSomeSmartCircular) {
  177. lastHoverIndex = currentHoverIndex;
  178. setCursor(Qt::PointingHandCursor);
  179. if (!hoverTimer.isActive()) {
  180. currentchangeLength = 0;
  181. hoverTimer.start();
  182. }
  183. } else {
  184. setCursor(Qt::ArrowCursor);
  185. }
  186. }
  187. settingMousPos = pos;
  188. }
  189. update();
  190. QWidget::mouseMoveEvent(event);
  191. }
  192. void PatternCodeLockWidget::onHoverTimer()
  193. {
  194. if (PatternCodeLockSetUpState == PatternCodeLockState::notSet) {
  195. if (mouseInSomeSmartCircular) {
  196. if (currentchangeLength >= (radiu * 0.2)) {
  197. hoverTimer.stop();
  198. }
  199. currentchangeLength += 2;
  200. } else {
  201. if (currentchangeLength <= -(radiu * 0.1)) {
  202. hoverTimer.stop();
  203. }
  204. currentchangeLength -= 2;
  205. }
  206. } else if (PatternCodeLockSetUpState == PatternCodeLockState::setting) {
  207. if (currentchangeLength >= (radiu * 0.1)) {
  208. hoverTimer.stop();
  209. }
  210. currentchangeLength += 2;
  211. }
  212. update();
  213. }
  214. void PatternCodeLockWidget::mousePressEvent(QMouseEvent *event)
  215. {
  216. if (lastHoverIndex != -1) {
  217. if (PatternCodeLockSetUpState == PatternCodeLockState::notSet) //开始设置
  218. {
  219. PatternCodeLockSetUpState = PatternCodeLockState::setting;
  220. setList << lastHoverIndex;
  221. circularStateList[lastHoverIndex] = CircularState::hoverOnInnerSamrtCircular;
  222. settingMousPos = event->pos();
  223. currentchangeLength = 0;
  224. hoverTimer.start();
  225. update();
  226. }
  227. }
  228. QWidget::mousePressEvent(event);
  229. }
  230. void PatternCodeLockWidget::mouseDoubleClickEvent(QMouseEvent *event)
  231. {
  232. if (PatternCodeLockSetUpState == PatternCodeLockState::setting && !mouseInSomeSmartCircular) {
  233. if (setList.size() < 4) {
  234. PatternCodeLockSetUpState = PatternCodeLockState::setted_invalid;
  235. emit setPassword("4位以下的无效密码");
  236. } else {
  237. PatternCodeLockSetUpState = PatternCodeLockState::setted_valid;
  238. emit setPassword(getPassWord());
  239. }
  240. update();
  241. }
  242. QWidget::mouseDoubleClickEvent(event);
  243. }
  244. QString PatternCodeLockWidget::getPassWord()
  245. {
  246. QString psw;
  247. for (const int &value : setList) {
  248. psw.append(QString::number(value, 16));
  249. }
  250. return psw;
  251. }
  252. int PatternCodeLockWidget::getNumberOfEachRowAndCol() const
  253. {
  254. return numberOfEachRowAndCol;
  255. }
  256. void PatternCodeLockWidget::setNumberOfEachRowAndCol(int newNumberOfEachRowAndCol)
  257. {
  258. if (newNumberOfEachRowAndCol > 1 && newNumberOfEachRowAndCol < 10) {
  259. reset();
  260. circularStateList.clear();
  261. smartCircularRectList.clear();
  262. numberOfEachRowAndCol = newNumberOfEachRowAndCol;
  263. for (int i = 0; i < numberOfEachRowAndCol; ++i) {
  264. for (int j = 0; j < numberOfEachRowAndCol; ++j) {
  265. circularStateList << CircularState::normal;
  266. smartCircularRectList << QRect();
  267. }
  268. }
  269. update();
  270. }
  271. }
  272. void PatternCodeLockWidget::reset()
  273. {
  274. PatternCodeLockSetUpState = PatternCodeLockState::notSet;
  275. std::fill(circularStateList.begin(), circularStateList.end(), CircularState::normal);
  276. lastHoverIndex = -1;
  277. hoverTimer.stop();
  278. currentchangeLength = 0;
  279. isUpdateSmartCircularRect = true;
  280. mouseInSomeSmartCircular = false;
  281. setList.clear();
  282. settingMousPos = QPoint(0, 0);
  283. update();
  284. }
  285. /************************ demo **************************************
  286. #include <QVBoxLayout>
  287. #include <QHBoxLayout>
  288. #include <QLabel>
  289. #include <QSpinBox>
  290. #include <QLineEdit>
  291. #include <QPushButton>
  292. int main(int argc, char *argv[])
  293. {
  294. QApplication a(argc, argv);
  295. PatternCodeLockWidget *w = new PatternCodeLockWidget(4);
  296. QWidget widget;
  297. auto hb = new QHBoxLayout;
  298. hb->addWidget(new QLabel("设置的密码:"));
  299. auto lineEdit = new QLineEdit;
  300. hb->addWidget(lineEdit);
  301. hb->addWidget(new QLabel("设置行列数:"));
  302. auto spinbox = new QSpinBox;
  303. spinbox->setRange(2, 9);
  304. spinbox->setMinimumWidth(100);
  305. spinbox->setValue(w->getNumberOfEachRowAndCol());
  306. hb->addWidget(spinbox);
  307. auto btn = new QPushButton("还原");
  308. hb->addWidget(btn);
  309. auto vb = new QVBoxLayout;
  310. vb->addWidget(w, 5);
  311. vb->addLayout(hb, 1);
  312. widget.setLayout(vb);
  313. QObject::connect(w, &PatternCodeLockWidget::setPassword, lineEdit, &QLineEdit::setText);
  314. QObject::connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), w,
  315. &PatternCodeLockWidget::setNumberOfEachRowAndCol);
  316. QObject::connect(btn, &QPushButton::clicked, w, &PatternCodeLockWidget::reset);
  317. widget.show();
  318. return a.exec();
  319. }
  320. *********************************************************************************/