"""Dracula PRO (Van Helsing) inspired themes.""" from __future__ import annotations from dataclasses import dataclass @dataclass(frozen=True) class Palette: name: str bg: str bg_secondary: str bg_input: str bg_button: str bg_button_hover: str bg_button_pressed: str border: str border_focus: str text: str text_dim: str text_bright: str accent: str accent_dim: str selection: str green: str green_bright: str orange: str pink: str purple: str red: str yellow: str tab_active: str tab_inactive: str scroll_handle: str scroll_hover: str log_rx: str log_tx: str log_info: str # Dracula PRO Van Helsing palette _D = dict( cyan="#80ffea", green="#8aff80", orange="#ffca80", pink="#ff80bf", purple="#9580ff", red="#ff9580", yellow="#ffff80", comment="#7970a9", ) DARK = Palette( name="dark", bg="#1e2029", bg_secondary="#282a36", bg_input="#313442", bg_button="#414458", bg_button_hover="#515570", bg_button_pressed="#363949", border="#414458", border_focus=_D["cyan"], text="#f8f8f2", text_dim=_D["comment"], text_bright="#ffffff", accent=_D["cyan"], accent_dim="#2a4a50", selection="#44475a", green=_D["green"], green_bright="#50fa7b", orange=_D["orange"], pink=_D["pink"], purple=_D["purple"], red=_D["red"], yellow=_D["yellow"], tab_active="#1e2029", tab_inactive="#282a36", scroll_handle="#44475a", scroll_hover="#515570", log_rx=_D["green"], log_tx=_D["cyan"], log_info=_D["comment"], ) LIGHT = Palette( name="light", bg="#ffffff", bg_secondary="#f4f4f8", bg_input="#ffffff", bg_button="#eeeef2", bg_button_hover="#dddde4", bg_button_pressed="#ccccd4", border="#d4d4dc", border_focus="#6c5ce7", text="#282a36", text_dim="#7970a9", text_bright="#1e2029", accent="#6c5ce7", accent_dim="#eae7fd", selection="#ddd8fd", green="#2ebc50", green_bright="#27ae60", orange="#e67e22", pink="#e84393", purple="#6c5ce7", red="#e74c3c", yellow="#f1c40f", tab_active="#ffffff", tab_inactive="#f4f4f8", scroll_handle="#c4c4cc", scroll_hover="#a4a4ac", log_rx="#1a8a3d", log_tx="#2944a8", log_info="#7970a9", ) def build_stylesheet(p: Palette) -> str: return f""" /* ── Dracula PRO Theme ────────────────────────────── */ * {{ outline: none; }} QWidget {{ background-color: {p.bg}; color: {p.text}; font-family: "Segoe UI", "SF Pro Text", sans-serif; font-size: 10pt; }} QMainWindow {{ background-color: {p.bg}; }} /* ── Menu ─────────────────────────────────────────── */ QMenuBar {{ background-color: {p.bg_secondary}; color: {p.text}; border-bottom: 1px solid {p.border}; padding: 2px; }} QMenuBar::item {{ padding: 5px 12px; border-radius: 4px; }} QMenuBar::item:selected {{ background-color: {p.selection}; }} QMenu {{ background-color: {p.bg_secondary}; color: {p.text}; border: 1px solid {p.border}; border-radius: 8px; padding: 4px; }} QMenu::item {{ padding: 6px 28px 6px 16px; border-radius: 4px; }} QMenu::item:selected {{ background-color: {p.accent}; color: {p.bg}; }} QMenu::separator {{ height: 1px; background: {p.border}; margin: 4px 8px; }} /* ── Tabs ─────────────────────────────────────────── */ QTabWidget::pane {{ border: 1px solid {p.border}; background: {p.bg}; top: -1px; }} QTabBar {{ background: {p.bg_secondary}; qproperty-drawBase: 0; }} QTabBar::tab {{ background: {p.tab_inactive}; color: {p.text_dim}; padding: 7px 18px; border: none; border-bottom: 2px solid transparent; margin-right: 1px; }} QTabBar::tab:selected {{ background: {p.tab_active}; color: {p.accent}; border-bottom: 2px solid {p.accent}; }} QTabBar::tab:hover:!selected {{ color: {p.text}; background: {p.bg_button}; }} /* ── GroupBox (Collapsible Card) ──────────────────── */ QGroupBox {{ background-color: {p.bg_secondary}; border: 1px solid {p.border}; border-radius: 8px; margin-top: 14px; padding: 10px 8px 8px 8px; font-weight: 600; }} QGroupBox::title {{ subcontrol-origin: margin; subcontrol-position: top left; padding: 2px 10px; color: {p.accent}; font-size: 10pt; }} QGroupBox::indicator {{ width: 0px; height: 0px; margin: 0px; padding: 0px; border: none; }} /* ── Buttons ──────────────────────────────────────── */ QPushButton {{ background-color: {p.bg_button}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; padding: 5px 14px; min-height: 24px; font-weight: 500; }} QPushButton:hover {{ background-color: {p.bg_button_hover}; border-color: {p.accent}; }} QPushButton:pressed {{ background-color: {p.bg_button_pressed}; }} QPushButton:disabled {{ color: {p.text_dim}; }} QPushButton[checkable="true"]:checked {{ background-color: {p.green}; color: {p.bg}; border-color: {p.green}; font-weight: bold; }} QPushButton[checkable="true"]:checked:hover {{ background-color: {p.green_bright}; }} /* ── Inputs ───────────────────────────────────────── */ QLineEdit {{ background-color: {p.bg_input}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; padding: 4px 8px; selection-background-color: {p.selection}; selection-color: {p.text_bright}; }} QLineEdit:focus {{ border: 1.5px solid {p.accent}; }} QComboBox {{ background-color: {p.bg_input}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; padding: 4px 8px; min-height: 24px; }} QComboBox:hover {{ border-color: {p.accent}; }} QComboBox::drop-down {{ border: none; width: 22px; }} QComboBox QAbstractItemView {{ background-color: {p.bg_secondary}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; selection-background-color: {p.accent}; selection-color: {p.bg}; padding: 4px; outline: none; }} QSpinBox {{ background-color: {p.bg_input}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; padding: 4px 8px; }} /* ── CheckBox ─────────────────────────────────────── */ QCheckBox {{ color: {p.text}; spacing: 6px; }} QCheckBox::indicator {{ width: 14px; height: 14px; border: 2px solid {p.text_dim}; border-radius: 4px; background: transparent; }} QCheckBox::indicator:checked {{ background: {p.accent}; border-color: {p.accent}; }} /* ── List ─────────────────────────────────────────── */ QListWidget {{ background-color: {p.bg_input}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; outline: none; padding: 2px; }} QListWidget::item {{ padding: 3px 8px; border-radius: 4px; }} QListWidget::item:selected {{ background-color: {p.selection}; color: {p.text_bright}; }} QListWidget::item:hover:!selected {{ background-color: {p.bg_button}; }} /* ── ScrollBar ────────────────────────────────────── */ QScrollBar:vertical {{ background: transparent; width: 8px; margin: 2px 0; }} QScrollBar::handle:vertical {{ background: {p.scroll_handle}; border-radius: 4px; min-height: 30px; }} QScrollBar::handle:vertical:hover {{ background: {p.scroll_hover}; }} QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{ height: 0; }} QScrollBar:horizontal {{ background: transparent; height: 8px; margin: 0 2px; }} QScrollBar::handle:horizontal {{ background: {p.scroll_handle}; border-radius: 4px; min-width: 30px; }} QScrollBar::handle:horizontal:hover {{ background: {p.scroll_hover}; }} QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {{ width: 0; }} /* ── Misc ─────────────────────────────────────────── */ QScrollArea {{ background: transparent; border: none; }} QSplitter::handle {{ background: {p.border}; width: 2px; }} QTextEdit {{ background-color: {p.bg_input}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; selection-background-color: {p.selection}; padding: 4px; }} QToolTip {{ background-color: {p.bg_secondary}; color: {p.text}; border: 1px solid {p.border}; border-radius: 6px; padding: 6px 10px; }} QDialog {{ background-color: {p.bg}; }} QDialogButtonBox QPushButton {{ min-width: 80px; }} QLabel {{ color: {p.text}; background: transparent; }} QToolButton {{ background: transparent; color: {p.text}; border: none; border-radius: 6px; padding: 4px 8px; font-size: 14pt; }} QToolButton:hover {{ background-color: {p.bg_button_hover}; }} """