| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 |
- #include "loginwindow.h"
- #include "qapplication.h"
- #include "qcolor.h"
- #include "qgroupbox.h"
- #include <QCheckBox>
- #include <QComboBox>
- #include <QDesktopServices>
- #include <QHBoxLayout>
- #include <QLabel>
- #include <QLineEdit>
- #include <QMap>
- #include <QMenu>
- #include <QMessageBox>
- #include <QPushButton>
- #include <QResizeEvent>
- #include <QSettings>
- #include <QTimer>
- #include <QTranslator>
- #include <QUrl>
- #include <QVBoxLayout>
- #include <thememanager.h>
- #include <widgets/maskoverlay.h>
- class QLabel;
- class QLineEdit;
- class QCheckBox;
- class QPushButton;
- class QComboBox;
- class LoginWidgetPrivate
- {
- public:
- explicit LoginWidgetPrivate(LoginWidget *q);
- ~LoginWidgetPrivate();
- void initialize();
- void setupMainLayout();
- void createFormContainer();
- void createBackgroundContainer();
- void createControlPanel();
- void updateLayoutPresentation();
- void applyCurrentTheme();
- void loadSettings();
- void saveSettings();
- void retranslateUi();
- LoginWidget *q_ptr;
- Q_DECLARE_PUBLIC(LoginWidget)
- // 配置和状态
- LoginWidget::Config config;
- LoginWidget::LayoutMode currentMode;
- bool rememberPassword;
- // UI组件
- QWidget *controlPanel;
- QWidget *formContainer;
- QWidget *backgroundContainer;
- QWidget *customFormWidget = nullptr;
- QHBoxLayout *mainContentLayout;
- // 表单控件
- QLineEdit *usernameEdit;
- QLineEdit *passwordEdit;
- QCheckBox *rememberCheck;
- QPushButton *loginBtn;
- // 控制面板组件
- QPushButton *layoutToggleBtn;
- QPushButton *darkModeBtn;
- QComboBox *languageCombo;
- QSettings settings;
- // 布局相关常量
- static constexpr int LAYOUT_SWITCH_THRESHOLD = 1024;
- static constexpr int FORM_RATIO = 34;
- static constexpr int BACKGROUND_RATIO = 66;
- private:
- QMenu *layoutMenu;
- void setupLayoutMenu();
- private:
- QPushButton *createSocialButton(const QString &iconPath);
- void setupSocialButtons(QVBoxLayout *layout);
- void setupDefaultForm(QVBoxLayout *layout);
- void handleWindowResize(int newWidth);
- QPushButton *createControlButton(const QString &text, const QString &objectName);
- };
- LoginWidgetPrivate::LoginWidgetPrivate(LoginWidget *q)
- : q_ptr(q)
- , currentMode(LoginWidget::RightForm)
- , rememberPassword(false)
- , controlPanel(nullptr)
- , formContainer(nullptr)
- , backgroundContainer(nullptr)
- , customFormWidget(nullptr)
- , mainContentLayout(nullptr)
- , usernameEdit(nullptr)
- , passwordEdit(nullptr)
- , rememberCheck(nullptr)
- , loginBtn(nullptr)
- , layoutToggleBtn(nullptr)
- , darkModeBtn(nullptr)
- , languageCombo(nullptr)
- {}
- LoginWidgetPrivate::~LoginWidgetPrivate()
- {
- if (customFormWidget)
- customFormWidget->deleteLater();
- }
- void LoginWidgetPrivate::initialize()
- {
- createFormContainer();
- createBackgroundContainer();
- createControlPanel();
- setupMainLayout();
- loadSettings();
- applyCurrentTheme();
- retranslateUi();
- }
- void LoginWidgetPrivate::setupMainLayout()
- {
- Q_Q(LoginWidget);
- QVBoxLayout *mainLayout = new QVBoxLayout(q);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- mainLayout->setSpacing(0);
- mainContentLayout = new QHBoxLayout();
- mainContentLayout->setContentsMargins(0, 0, 0, 0);
- mainContentLayout->setSpacing(0);
- // mainLayout->addLayout(controlLayout);
- mainLayout->addLayout(mainContentLayout);
- // 将控制面板设为顶层窗口的子部件
- controlPanel->setParent(q);
- controlPanel->raise(); // 确保在最上层
- updateLayoutPresentation();
- }
- void LoginWidgetPrivate::createFormContainer()
- {
- Q_Q(LoginWidget);
- if (formContainer) {
- formContainer->deleteLater();
- formContainer = nullptr;
- }
- formContainer = new QWidget(q);
- formContainer->setObjectName("formContainer");
- QVBoxLayout *formLayout = new QVBoxLayout(formContainer);
- if (config.allowFormCustomization && customFormWidget) {
- formLayout->addWidget(customFormWidget);
- return;
- }
- formLayout->addStretch();
- setupDefaultForm(formLayout);
- if (config.showSocialButtons) {
- setupSocialButtons(formLayout);
- }
- formLayout->addStretch();
- }
- void LoginWidgetPrivate::setupDefaultForm(QVBoxLayout *layout)
- {
- usernameEdit = new QLineEdit(formContainer);
- passwordEdit = new QLineEdit(formContainer);
- // passwordEdit->setEchoMode(QLineEdit::Password);
- rememberCheck = new QCheckBox(formContainer);
- loginBtn = new QPushButton(formContainer);
- layout->addWidget(new QLabel(("Username"), formContainer));
- layout->addWidget(usernameEdit);
- layout->addSpacing(15);
- layout->addWidget(new QLabel(("Password"), formContainer));
- layout->addWidget(passwordEdit);
- layout->addSpacing(10);
- layout->addWidget(rememberCheck);
- layout->addSpacing(15);
- layout->addWidget(loginBtn);
- layout->addSpacing(20);
- QObject::connect(loginBtn, &QPushButton::clicked, q_ptr, [this]() {
- Q_Q(LoginWidget);
- if (usernameEdit->text().isEmpty() || passwordEdit->text().isEmpty()) {
- QMessageBox::warning(q, ("Error"), ("Please fill all fields"));
- return;
- }
- emit q->loginRequested(usernameEdit->text(), passwordEdit->text());
- saveSettings();
- });
- }
- void LoginWidgetPrivate::setupSocialButtons(QVBoxLayout *layout)
- {
- QHBoxLayout *socialLayout = new QHBoxLayout();
- socialLayout->addStretch();
- QPushButton *wechatBtn = createSocialButton(":/icons/wechat.png");
- QPushButton *githubBtn = createSocialButton(":/icons/github.png");
- QObject::connect(wechatBtn, &QPushButton::clicked, q_ptr, &LoginWidget::wechatLoginRequested);
- QObject::connect(githubBtn, &QPushButton::clicked, q_ptr, &LoginWidget::githubLoginRequested);
- socialLayout->addWidget(wechatBtn);
- socialLayout->addWidget(githubBtn);
- socialLayout->addStretch();
- layout->addLayout(socialLayout);
- }
- QPushButton *LoginWidgetPrivate::createSocialButton(const QString &iconPath)
- {
- QPushButton *btn = new QPushButton(formContainer);
- btn->setIcon(QIcon(iconPath));
- btn->setIconSize(QSize(32, 32));
- btn->setFixedSize(48, 48);
- btn->setFlat(true);
- return btn;
- }
- void LoginWidgetPrivate::createBackgroundContainer()
- {
- Q_Q(LoginWidget);
- backgroundContainer = new QWidget(q);
- QLabel *description = new QLabel(("<h1>Secure Login</h1>"
- "<p>Version 2.0</p>"
- "<p>Advanced Security System</p>"),
- backgroundContainer);
- description->setAlignment(Qt::AlignCenter);
- QVBoxLayout *bgLayout = new QVBoxLayout(backgroundContainer);
- bgLayout->addWidget(description);
- }
- void LoginWidgetPrivate::createControlPanel()
- {
- Q_Q(LoginWidget);
- controlPanel = new QLabel(q);
- controlPanel->setObjectName("controlPanel");
- controlPanel->setFixedHeight(42);
- controlPanel->setMaximumHeight(42);
- QHBoxLayout *panelLayout = new QHBoxLayout(controlPanel);
- panelLayout->setSpacing(15); // 增加控件间距
- panelLayout->setContentsMargins(10, 0, 10, 0);
- panelLayout->setAlignment(Qt::AlignVCenter); // 居中对齐
- languageCombo = new QComboBox(controlPanel);
- languageCombo->addItem("中文", "zh_CN");
- languageCombo->addItem("English", "en_US");
- layoutToggleBtn = createControlButton("", "layoutToggle");
- layoutToggleBtn->setFixedSize(32, 32);
- layoutToggleBtn->setMaximumSize(32, 32);
- layoutToggleBtn->setStyleSheet(R"(
- QPushButton#layoutToggle {
- border: none;
- padding: 0px;
- margin: 0px;
- background-color: transparent;
- width: 32px;
- height: 32px;
- min-width: 32px;
- min-height: 32px;
- max-width: 32px;
- max-height: 32px;
- }
- )");
- // 创建并设置菜单
- setupLayoutMenu();
- darkModeBtn = createControlButton("", "darkToggle");
- darkModeBtn->setFixedSize(32, 32);
- darkModeBtn->setMaximumSize(32, 32);
- darkModeBtn->setCursor(Qt::PointingHandCursor);
- darkModeBtn->setStyleSheet(R"(
- QPushButton#darkToggle {
- border: none;
- padding: 0px;
- margin: 0px;
- background-color: transparent;
- width: 32px;
- height: 32px;
- min-width: 32px;
- min-height: 32px;
- max-width: 32px;
- max-height: 32px;
- }
- )");
- darkModeBtn->setIcon(QIcon(":/theme/dark_mode.svg"));
- darkModeBtn->setIconSize(QSize(24, 24));
- darkModeBtn->setToolTip("切换暗黑模式");
- panelLayout->addStretch();
- panelLayout->addWidget(languageCombo);
- panelLayout->addWidget(layoutToggleBtn);
- panelLayout->addWidget(darkModeBtn);
- panelLayout->addStretch();
- panelLayout->setSizeConstraint(QLayout::SetFixedSize);
- QObject::connect(layoutToggleBtn, &QPushButton::clicked, q, [this]() {
- if (q_ptr->width() < LAYOUT_SWITCH_THRESHOLD)
- return;
- // 在按钮下方显示菜单
- QPoint pos = layoutToggleBtn->mapToGlobal(layoutToggleBtn->rect().bottomLeft());
- layoutMenu->exec(pos);
- //currentMode = static_cast<LoginWidget::LayoutMode>((currentMode + 1) % 3);
- //updateLayoutPresentation();
- });
- QObject::connect(darkModeBtn, &QPushButton::clicked, q, [this]() {
- ThemeManager::instance().toggleThemeMode();
- applyCurrentTheme();
- });
- QObject::connect(&ThemeManager::instance(), &ThemeManager::themeChanged, q, [this]() {
- applyCurrentTheme();
- });
- QObject::connect(languageCombo,
- QOverload<int>::of(&QComboBox::currentIndexChanged),
- q,
- [this](int index) {
- QString locale = languageCombo->itemData(index).toString();
- QTranslator translator;
- if (translator.load(":/i18n/" + locale + ".qm")) {
- qApp->installTranslator(&translator);
- retranslateUi();
- }
- });
- }
- QPushButton *LoginWidgetPrivate::createControlButton(const QString &text, const QString &objectName)
- {
- QPushButton *btn = new QPushButton(text, controlPanel);
- btn->setObjectName(objectName);
- btn->setFixedSize(80, 30);
- return btn;
- }
- void LoginWidgetPrivate::updateLayoutPresentation()
- {
- QLayoutItem *item;
- while ((item = mainContentLayout->takeAt(0)) != nullptr) {
- delete item;
- }
- switch (currentMode) {
- case LoginWidget::CenterForm:
- mainContentLayout->addStretch();
- mainContentLayout->addWidget(formContainer);
- mainContentLayout->addStretch();
- backgroundContainer->setGeometry(q_ptr->rect());
- backgroundContainer->lower();
- break;
- case LoginWidget::LeftForm:
- mainContentLayout->addWidget(formContainer, FORM_RATIO);
- mainContentLayout->addWidget(backgroundContainer, BACKGROUND_RATIO);
- break;
- case LoginWidget::RightForm:
- mainContentLayout->addWidget(backgroundContainer, BACKGROUND_RATIO);
- mainContentLayout->addWidget(formContainer, FORM_RATIO);
- break;
- }
- //backgroundContainer->setVisible(currentMode != LoginWidget::CenterForm);
- applyCurrentTheme();
- }
- void LoginWidgetPrivate::applyCurrentTheme()
- {
- const ThemeManager &themeManager = ThemeManager::instance();
- QColor primary = themeManager.color("colorPrimary");
- primary.setAlphaF(0.48);
- const QString primaryColor = QString("rgba(%1, %2, %3, %4)")
- .arg(primary.red())
- .arg(primary.green())
- .arg(primary.blue())
- .arg(primary.alpha());
- const QString bg = QString(R"Raw(QWidget {
- background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
- stop:0.3 rgba(7, 7, 9, %1),
- stop:0.48 %2,
- stop:0.64 rgba(7, 7, 9, %1));
- })Raw")
- .arg(themeManager.themeMode() == ThemeManager::ThemeMode::Dark ? 30 : 20)
- .arg(primaryColor);
- if (themeManager.themeMode() == ThemeManager::ThemeMode::Dark) {
- formContainer->setStyleSheet(R"Raw(QWidget#formContainer{background-color: #FF14161A;})Raw");
- darkModeBtn->setIcon(QIcon(":/theme/light_mode.svg"));
- darkModeBtn->setToolTip("切换亮色模式");
- } else {
- formContainer->setStyleSheet(R"Raw(QWidget#formContainer{background-color: #FFFFFFFF;})Raw");
- darkModeBtn->setIcon(QIcon(":/theme/dark_mode.svg"));
- darkModeBtn->setToolTip("切换暗黑模式");
- }
- backgroundContainer->setStyleSheet(bg);
- controlPanel->setStyleSheet(QString(R"RAW(
- QWidget#controlPanel {
- border-radius: 21px;
- color: %1;
- background-color: %2;
- padding: 5px;
- height: 42px;
- min-height: 42px;
- max-height: 42px;
- }
- )RAW")
- .arg(themeManager.color("colorText").name(QColor::HexArgb))
- .arg(themeManager.color("colorFill").name(QColor::HexArgb)));
- }
- void LoginWidgetPrivate::loadSettings()
- {
- usernameEdit->setText(settings.value("username", "test1").toString());
- passwordEdit->setText((settings.value("password", "123456").toByteArray()));
- rememberCheck->setChecked(settings.value("rememberPassword", false).toBool());
- }
- void LoginWidgetPrivate::saveSettings()
- {
- if (rememberCheck->isChecked()) {
- settings.setValue("username", usernameEdit->text());
- settings.setValue("password", QByteArray(passwordEdit->text().toUtf8()).toBase64());
- } else {
- settings.remove("username");
- settings.remove("password");
- }
- settings.setValue("rememberPassword", rememberCheck->isChecked());
- }
- void LoginWidgetPrivate::retranslateUi()
- {
- usernameEdit->setPlaceholderText(("Enter username"));
- passwordEdit->setPlaceholderText(("Enter password"));
- rememberCheck->setText(("Remember password"));
- loginBtn->setText(("Login"));
- }
- void LoginWidgetPrivate::setupLayoutMenu()
- {
- layoutMenu = new QMenu(q_ptr);
- layoutMenu->setObjectName("layoutMenu");
- QAction *centerAction = new QAction(QIcon(":/icons/layout_center.svg"), "居中布局", layoutMenu);
- QAction *leftAction = new QAction(QIcon(":/icons/layout_left.svg"), "左侧布局", layoutMenu);
- QAction *rightAction = new QAction(QIcon(":/icons/layout_right.svg"), "右侧布局", layoutMenu);
- layoutMenu->addAction(centerAction);
- layoutMenu->addAction(leftAction);
- layoutMenu->addAction(rightAction);
- // 设置当前布局图标和文本
- layoutToggleBtn->setIcon(QIcon(":/icons/layout_right.svg"));
- layoutToggleBtn->setIconSize(QSize(24, 24));
- // 连接菜单动作信号
- QObject::connect(centerAction, &QAction::triggered, q_ptr, [this, centerAction]() {
- currentMode = LoginWidget::CenterForm;
- layoutToggleBtn->setIcon(centerAction->icon());
- updateLayoutPresentation();
- });
- QObject::connect(leftAction, &QAction::triggered, q_ptr, [this, leftAction]() {
- currentMode = LoginWidget::LeftForm;
- layoutToggleBtn->setIcon(leftAction->icon());
- updateLayoutPresentation();
- });
- QObject::connect(rightAction, &QAction::triggered, q_ptr, [this, rightAction]() {
- currentMode = LoginWidget::RightForm;
- layoutToggleBtn->setIcon(rightAction->icon());
- updateLayoutPresentation();
- });
- }
- void LoginWidgetPrivate::handleWindowResize(int newWidth)
- {
- LoginWidget::LayoutMode detectedMode = currentMode;
- if (newWidth < LAYOUT_SWITCH_THRESHOLD) {
- detectedMode = LoginWidget::CenterForm;
- }
- if (detectedMode != currentMode) {
- currentMode = detectedMode;
- updateLayoutPresentation();
- }
- layoutToggleBtn->setVisible(newWidth >= LAYOUT_SWITCH_THRESHOLD);
- if (currentMode == LoginWidget::CenterForm) {
- backgroundContainer->setGeometry(q_ptr->rect());
- }
- if (!controlPanel)
- return;
- const int margin = 10;
- controlPanel->move(newWidth - controlPanel->width() - margin, margin);
- }
- // Public class implementation
- LoginWidget::LoginWidget(QWidget *parent)
- : QWidget(parent)
- , d_ptr(new LoginWidgetPrivate(this))
- {
- Q_D(LoginWidget);
- d->initialize();
- }
- LoginWidget::~LoginWidget() = default;
- void LoginWidget::setConfig(const Config &config)
- {
- Q_D(LoginWidget);
- if (d->config.showSocialButtons != config.showSocialButtons
- || d->config.allowFormCustomization != config.allowFormCustomization) {
- d->config = config;
- d->createFormContainer();
- d->updateLayoutPresentation();
- }
- d->config = config;
- }
- LoginWidget::Config LoginWidget::config() const
- {
- Q_D(const LoginWidget);
- return d->config;
- }
- void LoginWidget::setCustomFormWidget(QWidget *widget)
- {
- Q_D(LoginWidget);
- if (d->customFormWidget) {
- d->customFormWidget->deleteLater();
- }
- d->customFormWidget = widget;
- if (d->config.allowFormCustomization) {
- d->createFormContainer();
- d->updateLayoutPresentation();
- }
- }
- QWidget *LoginWidget::takeCustomFormWidget()
- {
- Q_D(LoginWidget);
- QWidget *widget = d->customFormWidget;
- d->customFormWidget = nullptr;
- return widget;
- }
- QWidget *LoginWidget::formWidget() const
- {
- Q_D(const LoginWidget);
- return d->customFormWidget ? d->customFormWidget : d->formContainer;
- }
- void LoginWidget::resizeEvent(QResizeEvent *event)
- {
- Q_D(LoginWidget);
- QWidget::resizeEvent(event);
- d->handleWindowResize(event->size().width());
- }
- void LoginWidget::changeEvent(QEvent *event)
- {
- Q_D(LoginWidget);
- if (event->type() == QEvent::LanguageChange) {
- d->retranslateUi();
- }
- QWidget::changeEvent(event);
- }
- void LoginWidget::showEvent(QShowEvent *event)
- {
- Q_D(LoginWidget);
- QWidget::showEvent(event);
- d->handleWindowResize(width());
- }
|