319 lines
7.9 KiB
C++

#include "dialogcontrolpassword.h"
#include "ui_dialogcontrolpassword.h"
#include <QFont>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QLabel>
#include <QList>
#include <QPushButton>
#include <QShowEvent>
#include <QSizePolicy>
#include <QTimer>
namespace {
const char* kDigitBoxStyleEmpty =
"color: rgb(221, 225, 233);"
"background-color: rgb(47, 48, 52);"
"border: 1px solid rgb(70, 72, 78);"
"border-radius: 4px;";
const char* kDigitBoxStyleFilled =
"color: rgb(221, 225, 233);"
"background-color: rgb(60, 120, 180);"
"border: 1px solid rgb(80, 140, 200);"
"border-radius: 4px;";
const char* kKeypadButtonStyle =
"QPushButton {"
" background-color: rgb(47, 48, 52);"
" color: rgb(221, 225, 233);"
" border: 1px solid rgb(70, 72, 78);"
" border-radius: 4px;"
"}"
"QPushButton:hover {"
" background-color: rgb(70, 72, 78);"
"}"
"QPushButton:pressed {"
" background-color: rgb(40, 100, 160);"
"}";
QPushButton* MakeKeypadButton(QWidget* parent, const QString& text)
{
auto* button = new QPushButton(text, parent);
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
button->setMinimumSize(90, 72);
button->setFocusPolicy(Qt::NoFocus);
button->setStyleSheet(QString::fromLatin1(kKeypadButtonStyle));
QFont font = button->font();
font.setPointSize(22);
font.setBold(true);
button->setFont(font);
return button;
}
} // namespace
DialogControlPassword::DialogControlPassword(QWidget* parent)
: QDialog(parent)
, ui(new Ui::DialogControlPassword)
{
ui->setupUi(this);
setModal(true);
setWindowModality(Qt::ApplicationModal);
setFixedSize(520, 720);
setFocusPolicy(Qt::StrongFocus);
if (ui->btnOK) {
ui->btnOK->setFocusPolicy(Qt::NoFocus);
}
if (ui->btnCancel) {
ui->btnCancel->setFocusPolicy(Qt::NoFocus);
}
ApplyUiFont();
if (ui->label_title) {
QFont titleFont = ui->label_title->font();
titleFont.setPointSize(20);
titleFont.setBold(true);
ui->label_title->setFont(titleFont);
}
BuildDigitBoxes();
BuildKeypad();
UpdateOkEnabled();
}
DialogControlPassword::~DialogControlPassword()
{
delete ui;
}
void DialogControlPassword::SetTitle(const QString& title)
{
const QString windowTitle = title.isEmpty()
? QStringLiteral("控制密码")
: title;
setWindowTitle(windowTitle);
if (ui && ui->label_title) {
ui->label_title->setText(windowTitle);
}
}
QString DialogControlPassword::Password() const
{
return m_password;
}
void DialogControlPassword::SetError(const QString& text)
{
if (!ui || !ui->label_error) {
return;
}
ui->label_error->setText(text);
}
void DialogControlPassword::SetPasswordChecker(
const std::function<bool(const QString&)>& checker)
{
m_passwordChecker = checker;
}
void DialogControlPassword::on_btnOK_clicked()
{
TryAccept();
}
void DialogControlPassword::on_btnCancel_clicked()
{
reject();
}
void DialogControlPassword::ApplyUiFont()
{
QFont font;
font.setPointSize(16);
setFont(font);
const QList<QWidget*> widgets = findChildren<QWidget*>();
for (QWidget* widget : widgets) {
widget->setFont(font);
}
}
void DialogControlPassword::BuildDigitBoxes()
{
if (!ui || !ui->widget_digits) {
return;
}
auto* layout = new QHBoxLayout(ui->widget_digits);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(10);
m_digitLabels.clear();
m_digitLabels.reserve(kPasswordLength);
for (int i = 0; i < kPasswordLength; ++i) {
auto* digitLabel = new QLabel(ui->widget_digits);
digitLabel->setAlignment(Qt::AlignCenter);
digitLabel->setMinimumSize(56, 56);
QFont digitFont = digitLabel->font();
digitFont.setPointSize(22);
digitFont.setBold(true);
digitLabel->setFont(digitFont);
layout->addWidget(digitLabel);
m_digitLabels.append(digitLabel);
}
RefreshDigits();
}
void DialogControlPassword::BuildKeypad()
{
if (!ui || !ui->widget_keypad) {
return;
}
auto* layout = new QGridLayout(ui->widget_keypad);
layout->setContentsMargins(0, 0, 0, 0);
layout->setHorizontalSpacing(12);
layout->setVerticalSpacing(12);
const int keys[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < 9; ++i) {
const int digit = keys[i];
QPushButton* button = MakeKeypadButton(
ui->widget_keypad,
QString::number(digit));
connect(button, &QPushButton::clicked, this, [this, digit]() {
AppendDigit(QChar('0' + digit));
});
layout->addWidget(button, i / 3, i % 3);
}
QPushButton* backButton = MakeKeypadButton(
ui->widget_keypad,
QStringLiteral("删除"));
connect(backButton, &QPushButton::clicked, this, [this]() {
RemoveLastDigit();
});
layout->addWidget(backButton, 3, 0);
QPushButton* zeroButton = MakeKeypadButton(
ui->widget_keypad,
QStringLiteral("0"));
connect(zeroButton, &QPushButton::clicked, this, [this]() {
AppendDigit(QLatin1Char('0'));
});
layout->addWidget(zeroButton, 3, 1);
QPushButton* clearButton = MakeKeypadButton(
ui->widget_keypad,
QStringLiteral("清空"));
connect(clearButton, &QPushButton::clicked, this, [this]() {
ClearPassword();
});
layout->addWidget(clearButton, 3, 2);
}
void DialogControlPassword::AppendDigit(QChar digit)
{
if (!digit.isDigit() || m_password.size() >= kPasswordLength) {
return;
}
m_password.append(digit);
SetError(QString());
RefreshDigits();
// 满 6 位后自动校验,正确关闭窗口,错误提示并清空。
if (m_password.size() == kPasswordLength) {
QTimer::singleShot(50, this, [this]() {
TryAccept();
});
}
}
void DialogControlPassword::RemoveLastDigit()
{
if (m_password.isEmpty()) {
return;
}
m_password.chop(1);
SetError(QString());
RefreshDigits();
}
void DialogControlPassword::ClearPassword()
{
if (m_password.isEmpty()) {
RefreshDigits();
return;
}
m_password.clear();
RefreshDigits();
}
void DialogControlPassword::RefreshDigits()
{
for (int i = 0; i < m_digitLabels.size(); ++i) {
QLabel* digitLabel = m_digitLabels[i];
if (!digitLabel) {
continue;
}
const bool filled = i < m_password.size();
digitLabel->setText(filled ? QStringLiteral("●") : QString());
digitLabel->setStyleSheet(QString::fromLatin1(
filled ? kDigitBoxStyleFilled : kDigitBoxStyleEmpty));
}
UpdateOkEnabled();
}
void DialogControlPassword::UpdateOkEnabled()
{
if (ui && ui->btnOK) {
ui->btnOK->setEnabled(m_password.size() == kPasswordLength);
}
}
void DialogControlPassword::TryAccept()
{
if (m_password.size() != kPasswordLength) {
SetError(QStringLiteral("请输入6位数字密码"));
return;
}
if (m_passwordChecker && !m_passwordChecker(m_password)) {
SetError(QStringLiteral("密码错误"));
ClearPassword();
return;
}
accept();
}
void DialogControlPassword::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
ClearPassword();
SetError(QString());
setFocus();
}
void DialogControlPassword::keyPressEvent(QKeyEvent* event)
{
if (!event) {
return;
}
if (event->key() == Qt::Key_Escape) {
reject();
return;
}
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
on_btnOK_clicked();
return;
}
if (event->key() == Qt::Key_Backspace) {
RemoveLastDigit();
return;
}
const QString text = event->text();
if (text.size() == 1 && text[0].isDigit()) {
AppendDigit(text[0]);
return;
}
QDialog::keyPressEvent(event);
}