""" 主题管理:亮色 / 暗色 QSS 样式表 持久化到 ~/.sshclient/settings.json """ import json from pathlib import Path CONFIG_DIR = Path.home() / ".sshclient" SETTINGS_FILE = CONFIG_DIR / "settings.json" DARK_QSS = """ QMainWindow, QWidget { background-color: #1e1e2e; color: #cdd6f4; } QMenuBar { background-color: #181825; color: #cdd6f4; border-bottom: 1px solid #313244; } QMenuBar::item:selected { background-color: #313244; } QMenu { background-color: #1e1e2e; color: #cdd6f4; border: 1px solid #313244; } QMenu::item:selected { background-color: #45475a; } QTabWidget::pane { border: 1px solid #313244; background: #1e1e2e; } QTabBar::tab { background: #181825; color: #a6adc8; padding: 6px 14px; border: 1px solid #313244; border-bottom: none; } QTabBar::tab:selected { background: #1e1e2e; color: #89b4fa; border-bottom: 2px solid #89b4fa; } QTabBar::tab:hover:!selected { background: #313244; } QListWidget { background-color: #181825; color: #cdd6f4; border: 1px solid #313244; alternate-background-color: #1e1e2e; } QListWidget::item:selected { background-color: #45475a; color: #89b4fa; } QPushButton { background-color: #313244; color: #cdd6f4; border: 1px solid #45475a; padding: 5px 12px; border-radius: 3px; } QPushButton:hover { background-color: #45475a; border-color: #89b4fa; } QPushButton:pressed { background-color: #585b70; } QPushButton:disabled { color: #585b70; background-color: #1e1e2e; } QLineEdit, QTextEdit, QPlainTextEdit, QComboBox, QSpinBox, QDoubleSpinBox { background-color: #181825; color: #cdd6f4; border: 1px solid #313244; padding: 3px 6px; border-radius: 2px; } QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus, QComboBox:focus { border-color: #89b4fa; } QComboBox::drop-down { border: none; } QComboBox QAbstractItemView { background-color: #1e1e2e; color: #cdd6f4; selection-background-color: #45475a; } QTableWidget { background-color: #181825; color: #cdd6f4; gridline-color: #313244; alternate-background-color: #1e1e2e; } QTableWidget::item:selected { background-color: #45475a; } QHeaderView::section { background-color: #313244; color: #cdd6f4; border: none; padding: 4px; border-right: 1px solid #45475a; } QTreeWidget { background-color: #181825; color: #cdd6f4; border: 1px solid #313244; } QTreeWidget::item:selected { background-color: #45475a; color: #89b4fa; } QProgressBar { background-color: #181825; border: 1px solid #313244; border-radius: 3px; text-align: center; color: #cdd6f4; } QProgressBar::chunk { background-color: #89b4fa; border-radius: 2px; } QGroupBox { border: 1px solid #313244; border-radius: 4px; margin-top: 8px; padding-top: 8px; color: #89b4fa; font-weight: bold; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 4px; } QLabel { color: #cdd6f4; } QStatusBar { background-color: #181825; color: #a6adc8; } QSplitter::handle { background-color: #313244; } QSplitter::handle:horizontal { width: 2px; } QSplitter::handle:vertical { height: 2px; } QScrollBar:vertical { background: #181825; width: 10px; border: none; } QScrollBar::handle:vertical { background: #45475a; min-height: 20px; border-radius: 4px; } QScrollBar::handle:vertical:hover { background: #585b70; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; } QScrollBar:horizontal { background: #181825; height: 10px; border: none; } QScrollBar::handle:horizontal { background: #45475a; min-width: 20px; border-radius: 4px; } QScrollBar::handle:horizontal:hover { background: #585b70; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; } QToolTip { background-color: #313244; color: #cdd6f4; border: 1px solid #45475a; padding: 4px; } QCheckBox { color: #cdd6f4; } QCheckBox::indicator { width: 14px; height: 14px; } QCheckBox::indicator:unchecked { background: #181825; border: 1px solid #45475a; border-radius: 2px; } QCheckBox::indicator:checked { background: #89b4fa; border: 1px solid #89b4fa; border-radius: 2px; } QDialog { background-color: #1e1e2e; } QFileDialog { background-color: #1e1e2e; } QMessageBox { background-color: #1e1e2e; } QMessageBox QLabel { color: #cdd6f4; } QToolButton { background-color: #313244; color: #cdd6f4; border: 1px solid #45475a; padding: 3px 6px; border-radius: 3px; } QToolButton:hover { background-color: #45475a; } """ LIGHT_QSS = """ QMainWindow, QWidget { background-color: #f5f5f5; color: #1a1a2e; } QTabWidget::pane { border: 1px solid #ddd; background: #fff; } QTabBar::tab { background: #e8e8e8; color: #555; padding: 6px 14px; border: 1px solid #ddd; border-bottom: none; } QTabBar::tab:selected { background: #fff; color: #1976d2; border-bottom: 2px solid #1976d2; } QListWidget { background-color: #fff; border: 1px solid #ddd; alternate-background-color: #f9f9f9; } QListWidget::item:selected { background-color: #e3f2fd; color: #1976d2; } QPushButton { background-color: #fff; color: #333; border: 1px solid #ccc; padding: 5px 12px; border-radius: 3px; } QPushButton:hover { background-color: #f0f0f0; border-color: #1976d2; } QLineEdit, QTextEdit, QPlainTextEdit, QComboBox, QSpinBox { background-color: #fff; color: #333; border: 1px solid #ccc; padding: 3px 6px; border-radius: 2px; } QLineEdit:focus, QTextEdit:focus { border-color: #1976d2; } QTableWidget { background-color: #fff; gridline-color: #e0e0e0; alternate-background-color: #f9f9f9; } QTableWidget::item:selected { background-color: #e3f2fd; } QHeaderView::section { background-color: #f0f0f0; color: #555; border: none; padding: 4px; border-right: 1px solid #ddd; } QGroupBox { border: 1px solid #ddd; border-radius: 4px; margin-top: 8px; padding-top: 8px; color: #1976d2; font-weight: bold; } QProgressBar { background-color: #f0f0f0; border: 1px solid #ddd; border-radius: 3px; text-align: center; } QProgressBar::chunk { background-color: #1976d2; border-radius: 2px; } QStatusBar { background-color: #f0f0f0; color: #666; } """ def load_settings() -> dict: if SETTINGS_FILE.exists(): try: with open(SETTINGS_FILE, "r", encoding="utf-8") as f: return json.load(f) except Exception: pass return {"theme": "light"} def save_settings(settings: dict): CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(SETTINGS_FILE, "w", encoding="utf-8") as f: json.dump(settings, f, ensure_ascii=False, indent=2) def get_theme() -> str: return load_settings().get("theme", "light") def set_theme(theme: str): s = load_settings() s["theme"] = theme save_settings(s) def get_qss(theme: "str | None" = None) -> str: if theme is None: theme = get_theme() return DARK_QSS if theme == "dark" else LIGHT_QSS