188 lines
5.4 KiB
Python
188 lines
5.4 KiB
Python
# Description: Theme system for EU-Utility
|
|
# Provides dark, light, and auto theme support
|
|
|
|
"""
|
|
EU-Utility Theme System
|
|
Supports Dark, Light, and Auto (system-based) themes
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QComboBox
|
|
from PyQt6.QtCore import Qt, QTimer, pyqtSignal
|
|
from PyQt6.QtGui import QColor, QPalette
|
|
import json
|
|
import os
|
|
|
|
|
|
class ThemeManager:
|
|
"""Central theme management for EU-Utility."""
|
|
|
|
theme_changed = pyqtSignal(str) # Emitted when theme changes
|
|
|
|
# Theme definitions
|
|
THEMES = {
|
|
'dark': {
|
|
'name': 'Dark',
|
|
'bg_primary': '#1a1a2e',
|
|
'bg_secondary': '#16213e',
|
|
'bg_tertiary': '#0f3460',
|
|
'accent': '#e94560',
|
|
'text_primary': '#ffffff',
|
|
'text_secondary': '#b8b8b8',
|
|
'border': '#2d2d44',
|
|
'success': '#4caf50',
|
|
'warning': '#ff9800',
|
|
'error': '#f44336',
|
|
},
|
|
'light': {
|
|
'name': 'Light',
|
|
'bg_primary': '#f5f5f5',
|
|
'bg_secondary': '#ffffff',
|
|
'bg_tertiary': '#e0e0e0',
|
|
'accent': '#2196f3',
|
|
'text_primary': '#212121',
|
|
'text_secondary': '#757575',
|
|
'border': '#bdbdbd',
|
|
'success': '#4caf50',
|
|
'warning': '#ff9800',
|
|
'error': '#f44336',
|
|
},
|
|
'eu_classic': {
|
|
'name': 'EU Classic',
|
|
'bg_primary': '#141f23',
|
|
'bg_secondary': '#1a2a30',
|
|
'bg_tertiary': '#0f1416',
|
|
'accent': '#ff8c42',
|
|
'text_primary': '#ffffff',
|
|
'text_secondary': '#a0a0a0',
|
|
'border': '#2a3a40',
|
|
'success': '#4ecdc4',
|
|
'warning': '#ff8c42',
|
|
'error': '#e74c3c',
|
|
}
|
|
}
|
|
|
|
_instance = None
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
cls._instance._initialized = False
|
|
return cls._instance
|
|
|
|
def __init__(self):
|
|
if self._initialized:
|
|
return
|
|
self._initialized = True
|
|
self.current_theme = 'eu_classic'
|
|
self.auto_theme = False
|
|
self._load_settings()
|
|
|
|
def _load_settings(self):
|
|
"""Load theme settings from file."""
|
|
try:
|
|
config_path = os.path.expanduser('~/.eu-utility/theme.json')
|
|
if os.path.exists(config_path):
|
|
with open(config_path, 'r') as f:
|
|
settings = json.load(f)
|
|
self.current_theme = settings.get('theme', 'eu_classic')
|
|
self.auto_theme = settings.get('auto', False)
|
|
except:
|
|
pass
|
|
|
|
def _save_settings(self):
|
|
"""Save theme settings to file."""
|
|
try:
|
|
config_dir = os.path.expanduser('~/.eu-utility')
|
|
os.makedirs(config_dir, exist_ok=True)
|
|
config_path = os.path.join(config_dir, 'theme.json')
|
|
with open(config_path, 'w') as f:
|
|
json.dump({
|
|
'theme': self.current_theme,
|
|
'auto': self.auto_theme
|
|
}, f)
|
|
except:
|
|
pass
|
|
|
|
def get_theme(self, name=None):
|
|
"""Get theme colors dictionary."""
|
|
if name is None:
|
|
name = self.current_theme
|
|
return self.THEMES.get(name, self.THEMES['eu_classic'])
|
|
|
|
def set_theme(self, name):
|
|
"""Set active theme."""
|
|
if name in self.THEMES:
|
|
self.current_theme = name
|
|
self._save_settings()
|
|
self.theme_changed.emit(name)
|
|
|
|
def get_stylesheet(self, theme_name=None):
|
|
"""Generate QSS stylesheet for theme."""
|
|
t = self.get_theme(theme_name)
|
|
|
|
return f"""
|
|
QWidget {{
|
|
background-color: {t['bg_primary']};
|
|
color: {t['text_primary']};
|
|
font-family: 'Segoe UI', sans-serif;
|
|
}}
|
|
|
|
QPushButton {{
|
|
background-color: {t['bg_tertiary']};
|
|
color: {t['text_primary']};
|
|
border: 1px solid {t['border']};
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
}}
|
|
|
|
QPushButton:hover {{
|
|
background-color: {t['accent']};
|
|
}}
|
|
|
|
QLineEdit, QTextEdit {{
|
|
background-color: {t['bg_secondary']};
|
|
color: {t['text_primary']};
|
|
border: 1px solid {t['border']};
|
|
padding: 6px;
|
|
border-radius: 4px;
|
|
}}
|
|
|
|
QLabel {{
|
|
color: {t['text_primary']};
|
|
}}
|
|
|
|
QComboBox {{
|
|
background-color: {t['bg_secondary']};
|
|
color: {t['text_primary']};
|
|
border: 1px solid {t['border']};
|
|
padding: 6px;
|
|
border-radius: 4px;
|
|
}}
|
|
|
|
QProgressBar {{
|
|
background-color: {t['bg_secondary']};
|
|
border: 1px solid {t['border']};
|
|
border-radius: 4px;
|
|
}}
|
|
|
|
QProgressBar::chunk {{
|
|
background-color: {t['accent']};
|
|
border-radius: 4px;
|
|
}}
|
|
|
|
QScrollBar:vertical {{
|
|
background-color: {t['bg_secondary']};
|
|
width: 12px;
|
|
border-radius: 6px;
|
|
}}
|
|
|
|
QScrollBar::handle:vertical {{
|
|
background-color: {t['border']};
|
|
border-radius: 6px;
|
|
}}
|
|
"""
|
|
|
|
|
|
# Global instance
|
|
theme_manager = ThemeManager()
|