8from __future__
import annotations
10from PyQt6.QtGui
import QColor
12SANS_FONT =
"Arial,Liberation Sans,DejaVu Sans,Helvetica,sans-serif"
16 """Native UI font family matching the application font, for QPainter text."""
17 from PyQt6.QtWidgets
import QApplication
19 app = QApplication.instance()
20 return app.font().family()
if app
is not None else SANS_FONT
27_LIGHT: dict[str, QColor] = {
28 "BG_DARK": QColor(
"#f5f7fa"),
29 "BG_MEDIUM": QColor(
"#ffffff"),
30 "BG_LIGHT": QColor(
"#fafbfc"),
31 "BG_TOPBAR": QColor(
"#ffffff"),
32 "PRIMARY": QColor(
"#334261"),
33 "PRIMARY_HOVER": QColor(
"#3d4f76"),
34 "PRIMARY_DARK": QColor(
"#27324b"),
35 "QUANTUM_CHANNEL": QColor(
"#8250df"),
36 "CLASSICAL_CHANNEL": QColor(
"#d9b112"),
37 "ENTANGLEMENT": QColor(
"#9527a3"),
38 "TEXT_PRIMARY": QColor(
"#334261"),
39 "TEXT_SECONDARY": QColor(
"#57606a"),
40 "TEXT_MUTED": QColor(
"#6e7781"),
41 "NODE_TEXT": QColor(
"#334261"),
42 "BORDER": QColor(
"#d0d7de"),
43 "QUBIT_PRODUCT": QColor(
"#0969da"),
44 "QUBIT_ENTANGLED": QColor(
"#9527a3"),
45 "QUBIT_MEASURED": QColor(
"#8c959f"),
46 "QUBIT_LOST": QColor(
"#da3633"),
47 "HALO_GATE": QColor(
"#475569"),
48 "HALO_MEASURE": QColor(
"#0e7c86"),
49 "HALO_GRAPH_MEASURE": QColor(
"#cf9a27"),
50 "PACKET_CLASSICAL": QColor(
"#d9b112"),
51 "PACKET_TCP": QColor(
"#1a7f37"),
52 "PACKET_UDP": QColor(
"#bc4c00"),
53 "CBIT": QColor(
"#cc6600"),
56_DARK: dict[str, QColor] = {
57 "BG_DARK": QColor(
"#0d1117"),
58 "BG_MEDIUM": QColor(
"#21262d"),
59 "BG_LIGHT": QColor(
"#2d333b"),
60 "BG_TOPBAR": QColor(
"#161b22"),
61 "PRIMARY": QColor(
"#334261"),
62 "PRIMARY_HOVER": QColor(
"#3d4f76"),
63 "PRIMARY_DARK": QColor(
"#27324b"),
64 "QUANTUM_CHANNEL": QColor(
"#a371f7"),
65 "CLASSICAL_CHANNEL": QColor(
"#e3b341"),
66 "ENTANGLEMENT": QColor(
"#d2a8ff"),
67 "TEXT_PRIMARY": QColor(
"#e6edf3"),
68 "TEXT_SECONDARY": QColor(
"#8d96a0"),
69 "TEXT_MUTED": QColor(
"#6e7681"),
70 "NODE_TEXT": QColor(
"#e6edf3"),
71 "BORDER": QColor(
"#30363d"),
72 "QUBIT_PRODUCT": QColor(
"#388bfd"),
73 "QUBIT_ENTANGLED": QColor(
"#d2a8ff"),
74 "QUBIT_MEASURED": QColor(
"#6e7681"),
75 "QUBIT_LOST": QColor(
"#f85149"),
76 "HALO_GATE": QColor(
"#94a3b8"),
77 "HALO_MEASURE": QColor(
"#39c5bb"),
78 "HALO_GRAPH_MEASURE": QColor(
"#e3b341"),
79 "PACKET_CLASSICAL": QColor(
"#e3b341"),
80 "PACKET_TCP": QColor(
"#3fb950"),
81 "PACKET_UDP": QColor(
"#f0883e"),
82 "CBIT": QColor(
"#ffa657"),
85_active_palette: dict[str, QColor] = _LIGHT
89 """Switch the active palette between light and dark.
91 @returns ``True`` if the palette is now dark; ``False`` if light.
93 global _active_palette
94 _active_palette = _DARK
if _active_palette
is _LIGHT
else _LIGHT
95 return _active_palette
is _DARK
99 """Return ``True`` when the dark palette is active."""
100 return _active_palette
is _DARK
109class _ThemeMeta(type):
110 """Metaclass that forwards attribute access to the active palette dict."""
112 def __getattr__(cls, name: str) -> QColor:
114 return _active_palette[name]
116 raise AttributeError(f
"Theme has no color attribute '{name}'")
from None
120 """Semantic color palette for Q2NSViz.
122 Access colors as class attributes (e.g. ``Theme.BG_DARK``). The active
123 palette (light or dark) is selected by calling ``toggle_dark()``.
125 **Qubit semantic states**
127 | Constant | Semantic |
129 | ``QUBIT_PRODUCT`` | Isolated qubit (no entanglement) |
130 | ``QUBIT_ENTANGLED`` | Qubit in an entanglement cluster |
131 | ``QUBIT_MEASURED`` | Measured and removed qubit marker |
132 | ``QUBIT_LOST`` | Lost qubit (removed without measurement) marker |
134 **Operation halos** (transient rings marking processing time during a
135 duration_ns window; entanglement itself is shown by qubit color, not a ring)
137 | Constant | Semantic | Symbol |
139 | ``HALO_GATE`` | quantum-gate processing (``entangle`` event) | dashed single |
140 | ``HALO_MEASURE`` | ``measure`` operation ring | solid single |
141 | ``HALO_GRAPH_MEASURE`` | ``graphMeasure`` operation ring | solid double |
143 **Classical packet types**
145 | Constant | Semantic |
147 | ``PACKET_CLASSICAL`` | Unknown or generic classical packet |
148 | ``PACKET_TCP`` | TCP classical packet |
149 | ``PACKET_UDP`` | UDP classical packet |
153__all__ = [
"SANS_FONT",
"Theme",
"is_dark",
"toggle_dark",
"ui_font_family"]
Semantic color palette for Q2NSViz.
bool toggle_dark()
Switch the active palette between light and dark.
bool is_dark()
Return True when the dark palette is active.
str ui_font_family()
Native UI font family matching the application font, for QPainter text.