"""Theme stylesheets for CmdForge GUI.""" from pathlib import Path # Light theme (default) LIGHT_THEME = """ /* Main Window */ QMainWindow { background-color: #f5f5f5; } /* Sidebar */ #sidebar { background-color: #2d3748; border: none; min-width: 180px; max-width: 180px; } #sidebar::item { color: #e2e8f0; padding: 12px 16px; border: none; border-left: 3px solid transparent; } #sidebar::item:selected { background-color: #4a5568; border-left: 3px solid #667eea; color: white; } #sidebar::item:hover:!selected { background-color: #3d4a5c; } /* Content area */ QWidget#content_area { background-color: #f7fafc; } /* Buttons */ QPushButton { background-color: #667eea; color: white; border: none; border-radius: 6px; padding: 8px 16px; font-weight: 500; min-height: 32px; } QPushButton:hover { background-color: #5a67d8; } QPushButton:pressed { background-color: #4c51bf; } QPushButton:disabled { background-color: #a0aec0; } QPushButton#secondary { background-color: #e2e8f0; color: #4a5568; } QPushButton#secondary:hover { background-color: #cbd5e0; } QPushButton#danger { background-color: #e53e3e; } QPushButton#danger:hover { background-color: #c53030; } /* View toggle buttons */ QPushButton#viewToggle { background-color: #e2e8f0; color: #4a5568; border-radius: 4px; padding: 6px 12px; min-height: 24px; min-width: 60px; } QPushButton#viewToggle:checked { background-color: #667eea; color: white; } QPushButton#viewToggle:hover:!checked { background-color: #cbd5e0; } /* Input fields */ QLineEdit, QTextEdit, QPlainTextEdit { border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px 12px; background-color: white; selection-background-color: #667eea; } QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus { border-color: #667eea; outline: none; } /* Combo boxes */ QComboBox { border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px 12px; background-color: white; min-height: 20px; } QComboBox:focus { border-color: #667eea; } QComboBox::drop-down { border: none; width: 24px; } QComboBox::down-arrow { image: none; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 6px solid #718096; margin-right: 8px; } QComboBox QAbstractItemView { border: 1px solid #e2e8f0; background-color: white; selection-background-color: #667eea; } /* Lists and Trees */ QListWidget, QTreeWidget, QTableWidget { border: 1px solid #e2e8f0; border-radius: 6px; background-color: white; outline: none; } QListWidget::item, QTreeWidget::item { padding: 8px 12px; border: none; } QListWidget::item:selected, QTreeWidget::item:selected { background-color: #667eea; color: white; } QListWidget::item:hover:!selected, QTreeWidget::item:hover:!selected { background-color: #edf2f7; } /* Table Widget */ QTableWidget { gridline-color: #e2e8f0; } QTableWidget::item { padding: 8px; } QTableWidget::item:selected { background-color: #667eea; color: white; } QHeaderView::section { background-color: #f7fafc; padding: 8px 12px; border: none; border-bottom: 1px solid #e2e8f0; font-weight: 600; color: #4a5568; } /* Group boxes */ QGroupBox { font-weight: 600; border: 1px solid #e2e8f0; border-radius: 8px; margin-top: 12px; padding-top: 12px; background-color: white; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 12px; padding: 0 8px; color: #2d3748; } /* Labels */ QLabel { color: #2d3748; } QLabel#heading { font-size: 18px; font-weight: 600; color: #1a202c; } QLabel#subheading { font-size: 14px; color: #718096; } QLabel#label { font-weight: 500; color: #4a5568; } QLabel#sectionHeading { font-weight: 600; font-size: 13px; color: #2d3748; } /* Scrollbars */ QScrollBar:vertical { background-color: #f7fafc; width: 12px; border-radius: 6px; } QScrollBar::handle:vertical { background-color: #cbd5e0; border-radius: 6px; min-height: 30px; } QScrollBar::handle:vertical:hover { background-color: #a0aec0; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; } QScrollBar:horizontal { background-color: #f7fafc; height: 12px; border-radius: 6px; } QScrollBar::handle:horizontal { background-color: #cbd5e0; border-radius: 6px; min-width: 30px; } QScrollBar::handle:horizontal:hover { background-color: #a0aec0; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; } /* Status bar */ QStatusBar { background-color: #f7fafc; border-top: 1px solid #e2e8f0; color: #718096; } /* Splitter */ QSplitter::handle { background-color: #e2e8f0; } QSplitter::handle:horizontal { width: 2px; } QSplitter::handle:vertical { height: 2px; } /* Tabs */ QTabWidget::pane { border: 1px solid #e2e8f0; border-radius: 6px; background-color: white; } QTabBar::tab { background-color: #edf2f7; border: 1px solid #e2e8f0; border-bottom: none; padding: 8px 16px; margin-right: 2px; border-top-left-radius: 6px; border-top-right-radius: 6px; } QTabBar::tab:selected { background-color: white; border-bottom: 1px solid white; } QTabBar::tab:hover:!selected { background-color: #e2e8f0; } /* Dialogs */ QDialog { background-color: #f7fafc; } /* Message boxes */ QMessageBox { background-color: #f7fafc; } QMessageBox QPushButton { min-width: 80px; } /* Tool tips */ QToolTip { background-color: #2d3748; color: white; border: none; padding: 6px 10px; border-radius: 4px; } /* Progress bar */ QProgressBar { border: 1px solid #e2e8f0; border-radius: 6px; background-color: #edf2f7; text-align: center; height: 20px; } QProgressBar::chunk { background-color: #667eea; border-radius: 5px; } /* Spin boxes */ QSpinBox, QDoubleSpinBox { border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px 12px; background-color: white; } QSpinBox:focus, QDoubleSpinBox:focus { border-color: #667eea; } /* Check boxes and radio buttons */ QCheckBox, QRadioButton { spacing: 8px; color: #2d3748; } QCheckBox::indicator, QRadioButton::indicator { width: 18px; height: 18px; } QCheckBox::indicator:unchecked { border: 2px solid #cbd5e0; border-radius: 4px; background-color: white; } QCheckBox::indicator:checked { border: 2px solid #667eea; border-radius: 4px; background-color: #667eea; } QRadioButton::indicator:unchecked { border: 2px solid #cbd5e0; border-radius: 9px; background-color: white; } QRadioButton::indicator:checked { border: 2px solid #667eea; border-radius: 9px; background-color: #667eea; } /* Menu bar */ QMenuBar { background-color: #f7fafc; border-bottom: 1px solid #e2e8f0; } QMenuBar::item { padding: 6px 12px; background-color: transparent; } QMenuBar::item:selected { background-color: #e2e8f0; } QMenu { background-color: white; border: 1px solid #e2e8f0; } QMenu::item { padding: 8px 24px; } QMenu::item:selected { background-color: #667eea; color: white; } QMenu::separator { height: 1px; background-color: #e2e8f0; margin: 4px 8px; } """ # Dark theme DARK_THEME = """ /* Main Window */ QMainWindow { background-color: #1a1a2e; } /* Sidebar */ #sidebar { background-color: #16213e; border: none; min-width: 180px; max-width: 180px; } #sidebar::item { color: #a0aec0; padding: 12px 16px; border: none; border-left: 3px solid transparent; } #sidebar::item:selected { background-color: #1f3460; border-left: 3px solid #667eea; color: white; } #sidebar::item:hover:!selected { background-color: #1a2d50; } /* Content area */ QWidget#content_area { background-color: #1a1a2e; } /* Buttons */ QPushButton { background-color: #667eea; color: white; border: none; border-radius: 6px; padding: 8px 16px; font-weight: 500; min-height: 32px; } QPushButton:hover { background-color: #7c8ff0; } QPushButton:pressed { background-color: #5a67d8; } QPushButton:disabled { background-color: #4a5568; color: #718096; } QPushButton#secondary { background-color: #2d3748; color: #e2e8f0; } QPushButton#secondary:hover { background-color: #4a5568; } QPushButton#danger { background-color: #e53e3e; } QPushButton#danger:hover { background-color: #fc5c65; } /* View toggle buttons */ QPushButton#viewToggle { background-color: #2d3748; color: #a0aec0; border-radius: 4px; padding: 6px 12px; min-height: 24px; min-width: 60px; } QPushButton#viewToggle:checked { background-color: #667eea; color: white; } QPushButton#viewToggle:hover:!checked { background-color: #4a5568; } /* Input fields */ QLineEdit, QTextEdit, QPlainTextEdit { border: 1px solid #4a5568; border-radius: 6px; padding: 8px 12px; background-color: #2d3748; color: #e2e8f0; selection-background-color: #667eea; } QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus { border-color: #667eea; outline: none; } /* Combo boxes */ QComboBox { border: 1px solid #4a5568; border-radius: 6px; padding: 8px 12px; background-color: #2d3748; color: #e2e8f0; min-height: 20px; } QComboBox:focus { border-color: #667eea; } QComboBox::drop-down { border: none; width: 24px; } QComboBox::down-arrow { image: none; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 6px solid #a0aec0; margin-right: 8px; } QComboBox QAbstractItemView { border: 1px solid #4a5568; background-color: #2d3748; color: #e2e8f0; selection-background-color: #667eea; } /* Lists and Trees */ QListWidget, QTreeWidget, QTableWidget { border: 1px solid #4a5568; border-radius: 6px; background-color: #2d3748; color: #e2e8f0; outline: none; } QListWidget::item, QTreeWidget::item { padding: 8px 12px; border: none; } QListWidget::item:selected, QTreeWidget::item:selected { background-color: #667eea; color: white; } QListWidget::item:hover:!selected, QTreeWidget::item:hover:!selected { background-color: #4a5568; } /* Table Widget */ QTableWidget { gridline-color: #4a5568; } QTableWidget::item { padding: 8px; } QTableWidget::item:selected { background-color: #667eea; color: white; } QHeaderView::section { background-color: #1a1a2e; padding: 8px 12px; border: none; border-bottom: 1px solid #4a5568; font-weight: 600; color: #a0aec0; } /* Group boxes */ QGroupBox { font-weight: 600; border: 1px solid #4a5568; border-radius: 8px; margin-top: 12px; padding-top: 12px; background-color: #2d3748; color: #e2e8f0; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left: 12px; padding: 0 8px; color: #e2e8f0; } /* Labels */ QLabel { color: #e2e8f0; } QLabel#heading { font-size: 18px; font-weight: 600; color: #ffffff; } QLabel#subheading { font-size: 14px; color: #a0aec0; } QLabel#label { font-weight: 500; color: #cbd5e0; } QLabel#sectionHeading { font-weight: 600; font-size: 13px; color: #e2e8f0; } /* Scrollbars */ QScrollBar:vertical { background-color: #1a1a2e; width: 12px; border-radius: 6px; } QScrollBar::handle:vertical { background-color: #4a5568; border-radius: 6px; min-height: 30px; } QScrollBar::handle:vertical:hover { background-color: #718096; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; } QScrollBar:horizontal { background-color: #1a1a2e; height: 12px; border-radius: 6px; } QScrollBar::handle:horizontal { background-color: #4a5568; border-radius: 6px; min-width: 30px; } QScrollBar::handle:horizontal:hover { background-color: #718096; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; } /* Status bar */ QStatusBar { background-color: #16213e; border-top: 1px solid #4a5568; color: #a0aec0; } /* Splitter */ QSplitter::handle { background-color: #4a5568; } QSplitter::handle:horizontal { width: 2px; } QSplitter::handle:vertical { height: 2px; } /* Tabs */ QTabWidget::pane { border: 1px solid #4a5568; border-radius: 6px; background-color: #2d3748; } QTabBar::tab { background-color: #1a1a2e; border: 1px solid #4a5568; border-bottom: none; padding: 8px 16px; margin-right: 2px; border-top-left-radius: 6px; border-top-right-radius: 6px; color: #a0aec0; } QTabBar::tab:selected { background-color: #2d3748; border-bottom: 1px solid #2d3748; color: #e2e8f0; } QTabBar::tab:hover:!selected { background-color: #16213e; } /* Dialogs */ QDialog { background-color: #1a1a2e; } /* Message boxes */ QMessageBox { background-color: #1a1a2e; } QMessageBox QPushButton { min-width: 80px; } /* Tool tips */ QToolTip { background-color: #4a5568; color: white; border: none; padding: 6px 10px; border-radius: 4px; } /* Progress bar */ QProgressBar { border: 1px solid #4a5568; border-radius: 6px; background-color: #2d3748; text-align: center; height: 20px; color: #e2e8f0; } QProgressBar::chunk { background-color: #667eea; border-radius: 5px; } /* Spin boxes */ QSpinBox, QDoubleSpinBox { border: 1px solid #4a5568; border-radius: 6px; padding: 8px 12px; background-color: #2d3748; color: #e2e8f0; } QSpinBox:focus, QDoubleSpinBox:focus { border-color: #667eea; } /* Check boxes and radio buttons */ QCheckBox, QRadioButton { spacing: 8px; color: #e2e8f0; } QCheckBox::indicator, QRadioButton::indicator { width: 18px; height: 18px; } QCheckBox::indicator:unchecked { border: 2px solid #4a5568; border-radius: 4px; background-color: #2d3748; } QCheckBox::indicator:checked { border: 2px solid #667eea; border-radius: 4px; background-color: #667eea; } QRadioButton::indicator:unchecked { border: 2px solid #4a5568; border-radius: 9px; background-color: #2d3748; } QRadioButton::indicator:checked { border: 2px solid #667eea; border-radius: 9px; background-color: #667eea; } /* Menu bar */ QMenuBar { background-color: #16213e; border-bottom: 1px solid #4a5568; color: #e2e8f0; } QMenuBar::item { padding: 6px 12px; background-color: transparent; } QMenuBar::item:selected { background-color: #1f3460; } QMenu { background-color: #2d3748; border: 1px solid #4a5568; color: #e2e8f0; } QMenu::item { padding: 8px 24px; } QMenu::item:selected { background-color: #667eea; color: white; } QMenu::separator { height: 1px; background-color: #4a5568; margin: 4px 8px; } """ # Available themes THEMES = { "light": LIGHT_THEME, "dark": DARK_THEME, } # For backwards compatibility STYLESHEET = LIGHT_THEME def get_custom_theme_path() -> Path: """Get path to custom theme file.""" return Path.home() / ".cmdforge" / "theme.qss" def load_theme(theme_name: str = "light") -> str: """ Load a theme stylesheet. Args: theme_name: Name of theme ("light", "dark") or "custom" for external file Returns: The stylesheet string """ # Check for custom theme file first custom_path = get_custom_theme_path() if theme_name == "custom" and custom_path.exists(): try: return custom_path.read_text() except Exception: pass # Fall back to light theme # Return built-in theme return THEMES.get(theme_name, LIGHT_THEME) def get_available_themes() -> list: """Get list of available theme names.""" themes = list(THEMES.keys()) if get_custom_theme_path().exists(): themes.append("custom") return themes