#include "loginwindow.h" #include "qapplication.h" #include "qcolor.h" #include "qgroupbox.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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(("

Secure Login

" "

Version 2.0

" "

Advanced Security System

"), 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((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::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", "admin").toString()); passwordEdit->setText((settings.value("password", "6MLAoh$#xR#0").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()); }