57092cad03
- ui/theme.py: light/dark QSS stylesheets, persisted to ~/.sshclient/settings.json - main_window.py: View menu with dark theme checkbox, applies on startup - ui/widgets.py: SparklineChart widget for mini trend visualization - MonitorPanel: CPU and memory sparkline charts showing last 60 samples - Charts cleared on stop/switch host
119 lines
6.5 KiB
Python
119 lines
6.5 KiB
Python
"""
|
|
主题管理:亮色 / 暗色 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
|