mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-18 07:23:03 +08:00
feat(theme): 新增 BlueForest 官方深色主题样式
- 新增 BlueForest.qss,基于 Fusion 控件规格的纯配色深色主题 - 深蓝底色 + 亮青绿强调色,控件尺寸与 Fusion 风格保持一致 - 全局统一 selection-background-color 为 #2dd4bf - 背景色分层:页面 > 头部栏 > 交互控件 > 弹出层 > 输入区 - Border 属性统一拆分为 style/color/width 三段式 - AppInitializer / ALSettingsWidget 配合主题加载 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,11 @@ import os
|
||||
from PySide6.QtCore import QStandardPaths, QDir
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
from gui.ALSettingsWidget import _applyTheme
|
||||
from gui.ALSettingsWidget import (
|
||||
_setActiveStyleName,
|
||||
_applyTheme,
|
||||
_applyQss,
|
||||
)
|
||||
from interfaces.ConfigProvider import CfgKey
|
||||
from managers.config.ConfigManager import instance as configInstance
|
||||
from managers.driver.WebDriverManager import instance as webdriverInstance
|
||||
@@ -76,7 +80,10 @@ def _initializeAppearance(
|
||||
cfg = configInstance()
|
||||
saved_style = cfg.get(CfgKey.GLOBAL.APPEARANCE.STYLE, "Fusion")
|
||||
saved_theme = cfg.get(CfgKey.GLOBAL.APPEARANCE.THEME, "system")
|
||||
saved_qss = cfg.get(CfgKey.GLOBAL.APPEARANCE.CUSTOM_QSS, "")
|
||||
app.setStyle(saved_style)
|
||||
_setActiveStyleName(saved_style)
|
||||
_applyQss(saved_qss)
|
||||
_applyTheme(saved_theme)
|
||||
|
||||
def initializeApp(
|
||||
|
||||
+31
-18
@@ -26,7 +26,6 @@ from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QFileDialog,
|
||||
QMessageBox,
|
||||
QStyle,
|
||||
QStyleFactory,
|
||||
QWidget
|
||||
)
|
||||
@@ -40,6 +39,16 @@ from interfaces.ConfigProvider import (
|
||||
)
|
||||
|
||||
|
||||
_active_style_name = ""
|
||||
|
||||
|
||||
def _setActiveStyleName(
|
||||
name: str
|
||||
):
|
||||
|
||||
global _active_style_name
|
||||
_active_style_name = name
|
||||
|
||||
def _clearQss(
|
||||
):
|
||||
|
||||
@@ -76,6 +85,7 @@ def _applyTheme(
|
||||
theme: str
|
||||
):
|
||||
|
||||
global _active_style_name
|
||||
app : QApplication | None = QApplication.instance()
|
||||
if not app:
|
||||
return
|
||||
@@ -85,7 +95,7 @@ def _applyTheme(
|
||||
app.styleHints().setColorScheme(Qt.ColorScheme.Light)
|
||||
else:
|
||||
app.styleHints().setColorScheme(Qt.ColorScheme.Unknown)
|
||||
app.setStyle(QStyleFactory.create(app.style().objectName()))
|
||||
app.setStyle(QStyleFactory.create(_active_style_name))
|
||||
|
||||
def _restartApp(
|
||||
):
|
||||
@@ -104,7 +114,7 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
):
|
||||
super().__init__(parent)
|
||||
self.__cfg_mgr: ConfigProvider = ConfigManager.instance()
|
||||
self.__original_style: QStyle | None = None
|
||||
self.__original_style: str = ""
|
||||
|
||||
self.setupUi(self)
|
||||
self.modifyUi()
|
||||
@@ -137,6 +147,12 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
self.StyleComboBox.clear()
|
||||
self.StyleComboBox.addItems(QStyleFactory.keys())
|
||||
|
||||
def currentStyleKey(
|
||||
self
|
||||
) -> str:
|
||||
|
||||
return _active_style_name
|
||||
|
||||
def connectSignals(
|
||||
self
|
||||
):
|
||||
@@ -184,7 +200,7 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
theme = self.__cfg_mgr.get(CfgKey.GLOBAL.APPEARANCE.THEME, "system")
|
||||
style = self.__cfg_mgr.get(CfgKey.GLOBAL.APPEARANCE.STYLE, "Fusion")
|
||||
custom_qss = self.__cfg_mgr.get(CfgKey.GLOBAL.APPEARANCE.CUSTOM_QSS, "")
|
||||
self.__original_style = QApplication.instance().style()
|
||||
self.__original_style = self.currentStyleKey()
|
||||
if theme == "light":
|
||||
self.LightThemeRadio.setChecked(True)
|
||||
elif theme == "dark":
|
||||
@@ -192,10 +208,9 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
else:
|
||||
self.SystemThemeRadio.setChecked(True)
|
||||
index = self.StyleComboBox.findText(style)
|
||||
if index >= 0:
|
||||
self.StyleComboBox.setCurrentIndex(index)
|
||||
else:
|
||||
self.StyleComboBox.setCurrentIndex(0)
|
||||
if index < 0:
|
||||
index = 0
|
||||
self.StyleComboBox.setCurrentIndex(index)
|
||||
self.QssPathEdit.setText(custom_qss)
|
||||
self.updateQssStatus(custom_qss)
|
||||
|
||||
@@ -205,7 +220,8 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
):
|
||||
|
||||
if qss_path and os.path.isfile(qss_path):
|
||||
self.QssStatusLabel.setText(f"已加载自定义样式文件:{qss_path}")
|
||||
filename = os.path.basename(qss_path)
|
||||
self.QssStatusLabel.setText(f"已加载自定义样式文件:{filename}")
|
||||
else:
|
||||
self.QssStatusLabel.setText("当前使用程序默认外观。")
|
||||
|
||||
@@ -219,7 +235,7 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
theme = "dark"
|
||||
else:
|
||||
theme = "system"
|
||||
style = QStyleFactory.create(self.StyleComboBox.currentText())
|
||||
style = self.StyleComboBox.currentText()
|
||||
custom_qss = self.QssPathEdit.text().strip()
|
||||
return theme, style, custom_qss
|
||||
|
||||
@@ -229,16 +245,13 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
|
||||
theme, style, custom_qss = self.collectSettings()
|
||||
self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.THEME, theme)
|
||||
self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.STYLE, style.name())
|
||||
self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.STYLE, style)
|
||||
self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.CUSTOM_QSS, custom_qss)
|
||||
if custom_qss and os.path.isfile(custom_qss):
|
||||
_applyQss(custom_qss)
|
||||
else:
|
||||
_clearQss()
|
||||
_applyQss(custom_qss)
|
||||
_applyTheme(theme)
|
||||
self.setNavigationIcons()
|
||||
self.updateQssStatus(custom_qss)
|
||||
self.__original_style = QApplication.instance().style()
|
||||
self.__original_style = self.currentStyleKey()
|
||||
|
||||
def maybeRestart(
|
||||
self
|
||||
@@ -322,7 +335,7 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
):
|
||||
|
||||
_, style, _ = self.collectSettings()
|
||||
style_changed = self.__original_style.name() != style.name()
|
||||
style_changed = self.__original_style != style
|
||||
self.saveAndApply()
|
||||
if style_changed:
|
||||
self.maybeRestart()
|
||||
@@ -333,7 +346,7 @@ class ALSettingsWidget(QWidget, Ui_ALSettingsWidget):
|
||||
):
|
||||
|
||||
_, style, _ = self.collectSettings()
|
||||
style_changed = self.__original_style.name() != style.name()
|
||||
style_changed = self.__original_style != style
|
||||
self.saveAndApply()
|
||||
if style_changed:
|
||||
self.maybeRestart()
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright (c) 2026 KenanZhu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided "as is", without any warranty of any kind.
|
||||
* You may use, modify, and distribute this file under the terms of the MIT License.
|
||||
* See the LICENSE file for details.
|
||||
*
|
||||
*
|
||||
* AutoLibrary Official Style Theme : BlueForest
|
||||
*/
|
||||
|
||||
/* ---- Global ---- */
|
||||
QWidget {
|
||||
background-color: #0f1a2e;
|
||||
color: #d0daf0;
|
||||
selection-background-color: #2dd4bf;
|
||||
selection-color: #0f1119;
|
||||
}
|
||||
QMainWindow::separator {
|
||||
background-color: #1c2840;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
/* ---- Menu Bar ---- */
|
||||
QMenuBar {
|
||||
background-color: #0f1628;
|
||||
border-bottom: 1px solid #1c2840;
|
||||
padding: 2px 6px;
|
||||
color: #d0daf0;
|
||||
}
|
||||
QMenuBar::item {
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QMenuBar::item:selected {
|
||||
background-color: #1c2840;
|
||||
}
|
||||
QMenu {
|
||||
background-color: #162038;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
padding: 4px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
QMenu::item {
|
||||
padding: 5px 15px 5px 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QMenu::item:selected {
|
||||
background-color: #2dd4bf;
|
||||
color: #0f1119;
|
||||
}
|
||||
QMenu::separator {
|
||||
height: 1px;
|
||||
background-color: #253250;
|
||||
margin: 4px 8px;
|
||||
}
|
||||
|
||||
/* ---- Button ---- */
|
||||
QPushButton {
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
color: #d0daf0;
|
||||
padding: 2px;
|
||||
background-color: #1c2840;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #243458;
|
||||
border-color: #334478;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #162038;
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: #162038;
|
||||
color: #5568a0;
|
||||
border-color: #1c2840;
|
||||
}
|
||||
QPushButton[default="true"] {
|
||||
background-color: #2dd4bf;
|
||||
color: #0f1119;
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QPushButton[default="true"]:hover {
|
||||
background-color: #3de0cc;
|
||||
}
|
||||
|
||||
/* ---- Input ---- */
|
||||
QLineEdit,
|
||||
QPlainTextEdit,
|
||||
QTextEdit,
|
||||
QSpinBox,
|
||||
QDoubleSpinBox,
|
||||
QDateEdit,
|
||||
QTimeEdit {
|
||||
background-color: #0a1020;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
padding: 4px 8px;
|
||||
color: #d0daf0;
|
||||
selection-background-color: #2dd4bf;
|
||||
selection-color: #0f1119;
|
||||
}
|
||||
QLineEdit:focus,
|
||||
QPlainTextEdit:focus,
|
||||
QTextEdit:focus,
|
||||
QSpinBox:focus,
|
||||
QDoubleSpinBox:focus,
|
||||
QDateEdit:focus,
|
||||
QTimeEdit:focus {
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QPlainTextEdit,
|
||||
QTextEdit {
|
||||
background-color: #0a1020;
|
||||
}
|
||||
|
||||
/* ---- Combo Box ---- */
|
||||
QComboBox {
|
||||
background-color: #1c2840;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
padding: 4px 10px;
|
||||
color: #d0daf0;
|
||||
}
|
||||
QComboBox:hover {
|
||||
border-color: #334478;
|
||||
}
|
||||
QComboBox:focus {
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QComboBox::drop-down {
|
||||
subcontrol-origin: padding;
|
||||
subcontrol-position: top right;
|
||||
width: 24px;
|
||||
border-left: 1px solid #253250;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
QComboBox::down-arrow {
|
||||
image: none;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-top: 6px solid #7888b8;
|
||||
margin-right: 6px;
|
||||
}
|
||||
QComboBox QAbstractItemView {
|
||||
background-color: #162038;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 4px;
|
||||
selection-background-color: #2dd4bf;
|
||||
selection-color: #0f1119;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ---- Check Box / Radio Button ---- */
|
||||
QCheckBox,
|
||||
QRadioButton {
|
||||
spacing: 8px;
|
||||
color: #d0daf0;
|
||||
}
|
||||
QCheckBox::indicator,
|
||||
QRadioButton::indicator {
|
||||
border-style: solid;
|
||||
border-color: #334478;
|
||||
border-width: 2px;
|
||||
border-radius: 3px;
|
||||
background-color: #0a1020;
|
||||
}
|
||||
QCheckBox::indicator:hover,
|
||||
QRadioButton::indicator:hover {
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #2dd4bf;
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QRadioButton::indicator {
|
||||
border-radius: 10px;
|
||||
}
|
||||
QRadioButton::indicator:checked {
|
||||
background-color: #2dd4bf;
|
||||
border-color: #2dd4bf;
|
||||
}
|
||||
QCheckBox::indicator:disabled,
|
||||
QRadioButton::indicator:disabled {
|
||||
border-color: #253250;
|
||||
background-color: #162038;
|
||||
}
|
||||
|
||||
/* ---- Group Box ---- */
|
||||
QGroupBox {
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 6px;
|
||||
margin-top: 12px;
|
||||
padding-top: 14px;
|
||||
color: #d0daf0;
|
||||
font-weight: bold;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 12px;
|
||||
padding: 0 6px;
|
||||
color: #8b9ad0;
|
||||
}
|
||||
|
||||
/* ---- Tab ---- */
|
||||
QTabWidget::pane {
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
background-color: #0f1a2e;
|
||||
top: -1px;
|
||||
}
|
||||
QTabBar::tab {
|
||||
background-color: #162038;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
padding: 6px 16px;
|
||||
margin-right: 2px;
|
||||
color: #7888b8;
|
||||
}
|
||||
QTabBar::tab:selected {
|
||||
background-color: #0f1a2e;
|
||||
color: #2dd4bf;
|
||||
border-bottom: 2px solid #2dd4bf;
|
||||
}
|
||||
QTabBar::tab:hover:!selected {
|
||||
background-color: #1c2840;
|
||||
color: #d0daf0;
|
||||
}
|
||||
|
||||
/* ---- List / Tree ---- */
|
||||
QListWidget,
|
||||
QTreeWidget,
|
||||
QTableWidget {
|
||||
background-color: #0a1020;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
color: #d0daf0;
|
||||
alternate-background-color: #101c30;
|
||||
}
|
||||
QListWidget::item,
|
||||
QTreeWidget::item,
|
||||
QTableWidget::item {
|
||||
padding: 5px 10px;
|
||||
border: none;
|
||||
}
|
||||
QListWidget::item:selected,
|
||||
QTreeWidget::item:selected,
|
||||
QTableWidget::item:selected {
|
||||
background-color: #2dd4bf;
|
||||
color: #0f1119;
|
||||
}
|
||||
QListWidget::item:hover:!selected,
|
||||
QTreeWidget::item:hover:!selected {
|
||||
background-color: #1c2840;
|
||||
}
|
||||
QHeaderView::section {
|
||||
background-color: #0f1628;
|
||||
border: none;
|
||||
border-right: 1px solid #253250;
|
||||
border-bottom: 1px solid #253250;
|
||||
padding: 6px 10px;
|
||||
color: #8b9ad0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---- Scroll Bar ---- */
|
||||
QScrollBar:vertical {
|
||||
background-color: #0f1a2e;
|
||||
width: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QScrollBar::handle:vertical {
|
||||
background-color: #334478;
|
||||
min-height: 30px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background-color: #5568a0;
|
||||
}
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
height: 0;
|
||||
}
|
||||
QScrollBar:horizontal {
|
||||
background-color: #0f1a2e;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QScrollBar::handle:horizontal {
|
||||
background-color: #334478;
|
||||
min-width: 30px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QScrollBar::handle:horizontal:hover {
|
||||
background-color: #5568a0;
|
||||
}
|
||||
QScrollBar::add-line:horizontal,
|
||||
QScrollBar::sub-line:horizontal {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* ---- Progress Bar ---- */
|
||||
QProgressBar {
|
||||
background-color: #0a1020;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 5px;
|
||||
height: 10px;
|
||||
text-align: center;
|
||||
color: #d0daf0;
|
||||
}
|
||||
QProgressBar::chunk {
|
||||
background-color: #2dd4bf;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* ---- Slider ---- */
|
||||
QSlider::groove:horizontal {
|
||||
background-color: #1c2840;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QSlider::handle:horizontal {
|
||||
background-color: #2dd4bf;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -5px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
QSlider::sub-page:horizontal {
|
||||
background-color: #2dd4bf;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* ---- Tool Tip ---- */
|
||||
QToolTip {
|
||||
background-color: #1c2840;
|
||||
border-style: solid;
|
||||
border-color: #2dd4bf;
|
||||
border-width: 1px;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
color: #d0daf0;
|
||||
}
|
||||
|
||||
/* ---- Status Bar ---- */
|
||||
QStatusBar {
|
||||
background-color: #0f1628;
|
||||
border-top: 1px solid #1c2840;
|
||||
color: #7888b8;
|
||||
}
|
||||
|
||||
/* ---- Splitter ---- */
|
||||
QSplitter::handle {
|
||||
background-color: #253250;
|
||||
margin: 1px;
|
||||
}
|
||||
QSplitter::handle:horizontal {
|
||||
width: 2px;
|
||||
}
|
||||
QSplitter::handle:vertical {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
/* ---- Dialog ---- */
|
||||
QDialog {
|
||||
background-color: #0f1a2e;
|
||||
}
|
||||
|
||||
/* ---- Date / Time Editor Drop-down ---- */
|
||||
QDateEdit::drop-down,
|
||||
QTimeEdit::drop-down {
|
||||
subcontrol-origin: padding;
|
||||
subcontrol-position: top right;
|
||||
width: 24px;
|
||||
border-left: 1px solid #253250;
|
||||
}
|
||||
QCalendarWidget {
|
||||
background-color: #162038;
|
||||
border-style: solid;
|
||||
border-color: #253250;
|
||||
border-width: 1px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
QCalendarWidget QToolButton {
|
||||
color: #d0daf0;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
QCalendarWidget QToolButton:hover {
|
||||
background-color: #1c2840;
|
||||
}
|
||||
QCalendarWidget QMenu {
|
||||
background-color: #162038;
|
||||
}
|
||||
|
||||
/* ---- Frame ---- */
|
||||
QFrame[frameShape="4"], /* HLine */
|
||||
QFrame[frameShape="5"] /* VLine */ {
|
||||
background-color: #253250;
|
||||
}
|
||||
@@ -7,13 +7,13 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>400</height>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>460</height>
|
||||
<height>500</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
|
||||
Reference in New Issue
Block a user