diff --git a/src/boot/AppInitializer.py b/src/boot/AppInitializer.py
index 4c0440e..11f8a50 100644
--- a/src/boot/AppInitializer.py
+++ b/src/boot/AppInitializer.py
@@ -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(
diff --git a/src/gui/ALSettingsWidget.py b/src/gui/ALSettingsWidget.py
index 1fe44fb..6ce37d2 100644
--- a/src/gui/ALSettingsWidget.py
+++ b/src/gui/ALSettingsWidget.py
@@ -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()
diff --git a/src/gui/resources/themes/BlueForest.qss b/src/gui/resources/themes/BlueForest.qss
new file mode 100644
index 0000000..b984848
--- /dev/null
+++ b/src/gui/resources/themes/BlueForest.qss
@@ -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;
+}
diff --git a/src/gui/resources/ui/ALTimerTaskAddDialog.ui b/src/gui/resources/ui/ALTimerTaskAddDialog.ui
index e2fc6c4..251a4e2 100644
--- a/src/gui/resources/ui/ALTimerTaskAddDialog.ui
+++ b/src/gui/resources/ui/ALTimerTaskAddDialog.ui
@@ -7,13 +7,13 @@
0
0
350
- 400
+ 500
350
- 460
+ 500