소스 검색

Merge branch 'claude/bold-bhabha-c49dc7' of nikita.babich/lf_mri_platform into dev

Nikita Babich 15 시간 전
부모
커밋
83f6ef7bea

+ 224 - 3
apps/gui/src/app_window.py

@@ -63,6 +63,229 @@ QToolBar {{
 }}
 """
 
+# Global dark stylesheet — scanning-tab palette applied across every widget.
+_GLOBAL_CSS = """
+QWidget {
+    background-color: #1a1a2e;
+    color: #ddddff;
+    font-size: 11px;
+}
+QMainWindow { background-color: #0f0f1e; }
+QDialog     { background-color: #1a1a2e; }
+
+/* ── group boxes ── */
+QGroupBox {
+    background: #1e1e38;
+    border: 1px solid #333355;
+    border-radius: 3px;
+    margin-top: 16px;
+    padding-top: 8px;
+    color: #8888aa;
+    font-size: 10px;
+}
+QGroupBox::title {
+    subcontrol-origin: margin;
+    subcontrol-position: top left;
+    left: 8px;
+    top: 2px;
+    color: #8888aa;
+}
+
+/* ── buttons ── */
+QPushButton {
+    background: #252535;
+    color: #ccccee;
+    border: 1px solid #333355;
+    border-radius: 3px;
+    padding: 4px 10px;
+    min-height: 22px;
+}
+QPushButton:hover    { background: #2a2a4a; border-color: #444466; }
+QPushButton:pressed  { background: #1e1e38; border-color: #f0c040; }
+QPushButton:disabled { background: #1e1e2e; color: #555577; border-color: #2a2a3a; }
+QPushButton:checked  {
+    background: #1e1e38;
+    color: #ffffff;
+    border-bottom: 2px solid #f0c040;
+}
+
+/* ── text inputs ── */
+QLineEdit, QTextEdit, QPlainTextEdit {
+    background: #16162a;
+    color: #ddddff;
+    border: 1px solid #333355;
+    border-radius: 2px;
+    padding: 2px 4px;
+    selection-background-color: #e65100;
+    selection-color: #ffffff;
+}
+QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus { border-color: #f0c040; }
+
+/* ── spin boxes ── */
+QSpinBox, QDoubleSpinBox {
+    background: #16162a;
+    color: #ddddff;
+    border: 1px solid #333355;
+    border-radius: 2px;
+    padding: 2px 4px;
+}
+QSpinBox:focus, QDoubleSpinBox:focus { border-color: #f0c040; }
+QSpinBox::up-button, QDoubleSpinBox::up-button,
+QSpinBox::down-button, QDoubleSpinBox::down-button {
+    background: #252535;
+    border: none;
+    width: 14px;
+}
+QSpinBox::up-button:hover,   QDoubleSpinBox::up-button:hover,
+QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover {
+    background: #2a2a4a;
+}
+
+/* ── combo boxes ── */
+QComboBox {
+    background: #252535;
+    color: #ccccee;
+    border: 1px solid #333355;
+    border-radius: 2px;
+    padding: 2px 4px;
+    min-height: 22px;
+}
+QComboBox:hover  { border-color: #444466; }
+QComboBox:focus  { border-color: #f0c040; }
+QComboBox::drop-down { border: none; width: 20px; }
+QComboBox QAbstractItemView {
+    background: #16162a;
+    color: #ddddff;
+    border: 1px solid #333355;
+    selection-background-color: #e65100;
+    selection-color: #ffffff;
+}
+
+/* ── tables ── */
+QTableWidget, QTableView {
+    background: #16162a;
+    color: #ddddff;
+    gridline-color: #333355;
+    border: 1px solid #2a2a4a;
+    selection-background-color: #252545;
+    selection-color: #ffffff;
+    alternate-background-color: #1e1e38;
+}
+QHeaderView::section {
+    background: #252535;
+    color: #aaaaaa;
+    border: 1px solid #333355;
+    padding: 4px;
+    font-size: 10px;
+}
+QHeaderView::section:hover { background: #2a2a4a; }
+QHeaderView { background: #252535; }
+
+/* ── list widgets ── */
+QListWidget {
+    background: #16162a;
+    color: #ddddff;
+    border: 1px solid #2a2a4a;
+}
+QListWidget::item           { padding: 2px; }
+QListWidget::item:selected  { background: #e65100; color: #ffffff; }
+QListWidget::item:hover     { background: #252545; }
+
+/* ── scroll bars ── */
+QScrollArea { background: #1a1a2e; border: none; }
+QScrollBar:vertical {
+    background: #16162a;
+    width: 8px;
+    border: none;
+}
+QScrollBar::handle:vertical {
+    background: #444466;
+    border-radius: 4px;
+    min-height: 20px;
+}
+QScrollBar::handle:vertical:hover { background: #f0c040; }
+QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; }
+QScrollBar:horizontal {
+    background: #16162a;
+    height: 8px;
+    border: none;
+}
+QScrollBar::handle:horizontal {
+    background: #444466;
+    border-radius: 4px;
+    min-width: 20px;
+}
+QScrollBar::handle:horizontal:hover { background: #f0c040; }
+QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; }
+
+/* ── splitters ── */
+QSplitter::handle           { background: #2a2a4a; }
+QSplitter::handle:horizontal { width: 4px; }
+QSplitter::handle:vertical   { height: 4px; }
+QSplitter::handle:hover      { background: #f0c040; }
+
+/* ── inner tab widgets ── */
+QTabWidget::pane { background: #1a1a2e; border: 1px solid #333355; }
+QTabBar::tab {
+    background: #1e1e38;
+    color: #555577;
+    border: 1px solid #333355;
+    padding: 4px 12px;
+    min-width: 80px;
+}
+QTabBar::tab:selected        { background: #252545; color: #ffffff; border-bottom: 2px solid #f0c040; }
+QTabBar::tab:hover:!selected { background: #222240; color: #aaaacc; }
+
+/* ── progress bars ── */
+QProgressBar {
+    background: #16162a;
+    border: 1px solid #333355;
+    border-radius: 2px;
+    text-align: center;
+    color: #ddddff;
+    max-height: 12px;
+}
+QProgressBar::chunk { background: #f0c040; border-radius: 2px; }
+
+/* ── labels ── */
+QLabel { background: transparent; color: #aaaaaa; }
+
+/* ── frames / separators ── */
+QFrame { border: none; }
+QFrame[frameShape="4"] { background: #333355; max-width: 1px; }
+QFrame[frameShape="5"] { background: #333355; max-height: 1px; }
+
+/* ── status bar ── */
+QStatusBar { background: #0c0c1a; color: #555577; font-size: 11px; }
+
+/* ── checkboxes ── */
+QCheckBox { color: #aaaaaa; spacing: 5px; background: transparent; }
+QCheckBox::indicator {
+    width: 13px; height: 13px;
+    background: #16162a;
+    border: 1px solid #333355;
+    border-radius: 2px;
+}
+QCheckBox::indicator:checked { background: #f0c040; border-color: #f0c040; }
+QCheckBox::indicator:hover   { border-color: #444466; }
+
+/* ── radio buttons ── */
+QRadioButton { color: #aaaaaa; spacing: 5px; background: transparent; }
+QRadioButton::indicator {
+    width: 13px; height: 13px;
+    background: #16162a;
+    border: 1px solid #333355;
+    border-radius: 7px;
+}
+QRadioButton::indicator:checked { background: #f0c040; border-color: #f0c040; }
+
+/* ── named toolbar / bar widgets ── */
+#ButtonBar, #SeqStatus, #FidToolBar, #SpecToolBar {
+    background: #16162a;
+    border-bottom: 1px solid #333355;
+}
+"""
+
 
 class LFMRIWindow(QMainWindow):
     """Unified LF-MRI application window."""
@@ -79,6 +302,7 @@ class LFMRIWindow(QMainWindow):
         super().__init__()
         self.setWindowTitle("LF-MRI System")
         self.setMinimumSize(960, 640)
+        QApplication.instance().setStyleSheet(_GLOBAL_CSS)
 
         self._hw_config_path = hw_config_path
         self._output_dir = output_dir
@@ -169,9 +393,6 @@ class LFMRIWindow(QMainWindow):
 
     def _build_status_bar(self) -> None:
         sb = QStatusBar()
-        sb.setStyleSheet(
-            "QStatusBar { background: #0c0c1a; color: #555577; font-size: 11px; }"
-        )
         self.setStatusBar(sb)
         sb.showMessage(f"Active: {_TAB_NAMES[0]}")
 

+ 11 - 6
apps/gui/src/gui/block_table.py

@@ -36,28 +36,33 @@ _BG: dict[str, QColor] = {
 # because they need to be clearly visible on any background.
 _STYLESHEET = """
 QTableWidget {
-    gridline-color: palette(mid);
+    gridline-color: #333355;
     font-size: 12px;
+    background: #16162a;
+    color: #ddddff;
+    border: 1px solid #2a2a4a;
 }
 QTableWidget::item {
     padding: 2px 4px;
 }
 QTableWidget::item:selected {
-    background-color: #1565c0;
+    background-color: #e65100;
     color: #ffffff;
 }
 QTableWidget::item:hover:!selected {
-    background-color: rgba(144, 202, 249, 60);
+    background-color: #252545;
 }
 QHeaderView::section {
+    background: #252535;
+    color: #aaaaaa;
     border: none;
-    border-bottom: 1px solid palette(mid);
-    border-right:  1px solid palette(mid);
+    border-bottom: 1px solid #333355;
+    border-right:  1px solid #333355;
     padding: 4px 6px;
     font-weight: bold;
 }
 QScrollBar:horizontal, QScrollBar:vertical {
-    background: palette(alternateBase);
+    background: #16162a;
 }
 """
 

+ 11 - 9
apps/gui/src/gui/plot_panel.py

@@ -91,8 +91,8 @@ class PlotPanel(QWidget):
         _dark = system_is_dark()
         pg.setConfigOptions(
             antialias=True,
-            background=QColor("#1e1e1e") if _dark else QColor("#ffffff"),
-            foreground="w" if _dark else "k",
+            background=QColor("#1a1a2e") if _dark else QColor("#f0f0f8"),
+            foreground=QColor("#ddddff") if _dark else QColor("#1a1a2e"),
         )
 
         root = QVBoxLayout(self)
@@ -103,7 +103,7 @@ class PlotPanel(QWidget):
         self._btn_bar = QWidget()
         self._btn_bar.setObjectName("PlotBtnBar")
         self._btn_bar.setStyleSheet(
-            "#PlotBtnBar { border-bottom: 1px solid palette(mid); }"
+            "#PlotBtnBar { background: #16162a; border-bottom: 1px solid #333355; }"
         )
         self._btn_lay = QHBoxLayout(self._btn_bar)
         self._btn_lay.setContentsMargins(6, 3, 6, 3)
@@ -434,15 +434,16 @@ class PlotPanel(QWidget):
         btn.setFixedHeight(20)
         btn.setStyleSheet(
             f"QPushButton {{"
-            f"  color: palette(mid); font-size: 11px;"
+            f"  color: #666688; font-size: 11px;"
             f"  padding: 0px 7px;"
-            f"  border: 1px solid palette(mid);"
+            f"  border: 1px solid #333355;"
             f"  border-radius: 3px;"
+            f"  background: #1e1e38;"
             f"}}"
             f"QPushButton:checked {{"
             f"  color: {color}; font-weight: bold;"
             f"  border-color: {color};"
-            f"  background: palette(alternateBase);"
+            f"  background: #16162a;"
             f"}}"
         )
         btn.toggled.connect(lambda checked, k=key: self._on_row_toggle(k, checked))
@@ -469,15 +470,16 @@ class PlotPanel(QWidget):
         btn.setFixedHeight(20)
         btn.setStyleSheet(
             f"QPushButton {{"
-            f"  color: palette(mid); font-size: 11px;"
+            f"  color: #666688; font-size: 11px;"
             f"  padding: 0px 7px;"
-            f"  border: 1px solid palette(mid);"
+            f"  border: 1px solid #333355;"
             f"  border-radius: 3px;"
+            f"  background: #1e1e38;"
             f"}}"
             f"QPushButton:checked {{"
             f"  color: {color}; font-weight: bold;"
             f"  border-color: {color};"
-            f"  background: palette(alternateBase);"
+            f"  background: #16162a;"
             f"}}"
         )
         btn.toggled.connect(

+ 14 - 14
apps/gui/src/gui/scheme_panel.py

@@ -139,22 +139,22 @@ class SchemePanel(QWidget):
         """
         if system_is_dark():
             return {
-                "bg":          QColor("#1e1e1e"),
-                "text":        QColor("#e4e4e4"),
-                "tick":        QColor("#888888"),
-                "border":      QColor("#454545"),
-                "placeholder": QColor("#606060"),
-                "ph_bg":       QColor("#262626"),
-                "sel_border":  QColor("#e4e4e4"),
+                "bg":          QColor("#1a1a2e"),
+                "text":        QColor("#ddddff"),
+                "tick":        QColor("#666688"),
+                "border":      QColor("#333355"),
+                "placeholder": QColor("#555577"),
+                "ph_bg":       QColor("#16162a"),
+                "sel_border":  QColor("#f0c040"),
             }
         return {
-            "bg":          QColor("#ffffff"),
-            "text":        QColor("#333333"),
-            "tick":        QColor("#555555"),
-            "border":      QColor("#cccccc"),
-            "placeholder": QColor("#9e9e9e"),
-            "ph_bg":       QColor("#f5f5f5"),
-            "sel_border":  QColor("#000000"),
+            "bg":          QColor("#f0f0f8"),
+            "text":        QColor("#1a1a2e"),
+            "tick":        QColor("#555577"),
+            "border":      QColor("#aaaacc"),
+            "placeholder": QColor("#7777aa"),
+            "ph_bg":       QColor("#e8e8f8"),
+            "sel_border":  QColor("#e65100"),
         }
 
     # -- painting -------------------------------------------------------------

+ 1 - 1
apps/gui/src/tabs/fid_tab.py

@@ -114,7 +114,7 @@ class FidTab(QWidget):
         bar = QWidget()
         bar.setObjectName("FidToolBar")
         bar.setStyleSheet(
-            "#FidToolBar { background: palette(window); border-bottom: 1px solid palette(mid); }"
+            "#FidToolBar { background: #16162a; border-bottom: 1px solid #333355; }"
         )
         lay = QHBoxLayout(bar)
         lay.setContentsMargins(6, 4, 6, 4)

+ 2 - 2
apps/gui/src/tabs/scanner_tab.py

@@ -148,7 +148,7 @@ class ScannerTab(QWidget):
         seq_lay = QVBoxLayout(seq_grp)
         self._seq_info_label = QLabel("No sequence loaded")
         self._seq_info_label.setWordWrap(True)
-        self._seq_info_label.setStyleSheet("color: palette(mid); font-style: italic;")
+        self._seq_info_label.setStyleSheet("color: #666688; font-style: italic;")
         self._seq_info_label.setFont(QFont("Courier New", 8))
         seq_lay.addWidget(self._seq_info_label)
         lay.addWidget(seq_grp)
@@ -159,7 +159,7 @@ class ScannerTab(QWidget):
         self._job_label = QLabel("- no job -")
         self._job_label.setFont(QFont("Courier New", 8))
         self._job_label.setWordWrap(True)
-        self._job_label.setStyleSheet("color: palette(mid);")
+        self._job_label.setStyleSheet("color: #666688;")
         job_lay.addWidget(self._job_label)
         lay.addWidget(job_grp)
 

+ 3 - 3
apps/gui/src/tabs/seq_interp_tab.py

@@ -126,7 +126,7 @@ class SeqInterpTab(QWidget):
         bar = QWidget()
         bar.setObjectName("ButtonBar")
         bar.setStyleSheet(
-            "#ButtonBar { background: palette(window); border-bottom: 1px solid palette(mid); }"
+            "#ButtonBar { background: #16162a; border-bottom: 1px solid #333355; }"
         )
         lay = QHBoxLayout(bar)
         lay.setContentsMargins(6, 4, 6, 4)
@@ -181,7 +181,7 @@ class SeqInterpTab(QWidget):
         bar = QWidget()
         bar.setObjectName("SeqStatus")
         bar.setStyleSheet(
-            "#SeqStatus { background: palette(window); border-bottom: 1px solid palette(mid); }"
+            "#SeqStatus { background: #16162a; border-bottom: 1px solid #333355; }"
         )
         lay = QHBoxLayout(bar)
         lay.setContentsMargins(8, 2, 8, 2)
@@ -251,7 +251,7 @@ class SeqInterpTab(QWidget):
         self._warn_list.setFont(QFont("Arial", 9))
         self._warn_list.setMaximumHeight(110)
         self._warn_list.setStyleSheet(
-            "QListWidget { color: palette(text); background: palette(alternateBase); } "
+            "QListWidget { color: #ddddff; background: #16162a; border: 1px solid #2a2a4a; } "
             "QListWidget::item { padding: 2px; }"
         )
         warn_lay.addWidget(self._warn_list)

+ 7 - 7
apps/gui/src/tabs/spectroscopy_tab.py

@@ -152,8 +152,8 @@ class SpectroscopyTab(QWidget):
         bar.setObjectName("SpecToolBar")
         bar.setStyleSheet(
             "#SpecToolBar {"
-            "  background: palette(window);"
-            "  border-bottom: 1px solid palette(mid);"
+            "  background: #16162a;"
+            "  border-bottom: 1px solid #333355;"
             "}"
         )
         lay = QHBoxLayout(bar)
@@ -344,8 +344,8 @@ class SpectroscopyTab(QWidget):
         _dark = system_is_dark()
         pg.setConfigOptions(
             antialias=True,
-            background=QColor("#1e1e1e") if _dark else QColor("#ffffff"),
-            foreground="w" if _dark else "k",
+            background=QColor("#1a1a2e") if _dark else QColor("#f0f0f8"),
+            foreground=QColor("#ddddff") if _dark else QColor("#1a1a2e"),
         )
         _cross = pg.mkPen(
             "#ffffff50" if _dark else "#00000050", width=1, style=Qt.DashLine
@@ -842,9 +842,9 @@ class SpectroscopyTab(QWidget):
         dark = system_is_dark()
         label = pg.TextItem(
             anchor=(0, 1),
-            color="#f5f6fa" if dark else "#111111",
-            fill=pg.mkBrush(18, 18, 28, 170) if dark else pg.mkBrush(255, 255, 255, 170),
-            border=pg.mkPen("#ffffff40" if dark else "#00000030"),
+            color="#ddddff" if dark else "#1a1a2e",
+            fill=pg.mkBrush(26, 26, 46, 200) if dark else pg.mkBrush(240, 240, 248, 200),
+            border=pg.mkPen("#f0c04060" if dark else "#1a1a2e30"),
         )
         label.setFont(QFont("Courier New", 8))
         label.setVisible(False)