Skip to content

Commit ff383ac

Browse files
committed
enh: fixed refractory errors
1 parent e498772 commit ff383ac

4 files changed

Lines changed: 101 additions & 104 deletions

File tree

src/clinical_dbs_annotator/views/base_view.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"""
77

88
from PySide6.QtGui import QIcon, QPixmap
9-
from PySide6.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QWidget
9+
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout, QWidget
1010

1111

1212
class BaseStepView(QWidget):
@@ -82,5 +82,7 @@ def legend_item(color: str, text: str, border: str) -> QWidget:
8282

8383
def refresh_theme_icons(self) -> None:
8484
"""Refresh icons that depend on the current theme (call after theme toggle)."""
85-
# Base implementation - subclasses can override to refresh specific buttons
86-
pass
85+
# Auto-discover all settings buttons by objectName pattern
86+
for btn in self.findChildren(QPushButton):
87+
if btn.objectName() and "settings" in btn.objectName().lower():
88+
btn.setIcon(self._create_settings_icon())

src/clinical_dbs_annotator/views/step1_view.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ def __init__(self, parent_style=None):
100100

101101
self._setup_ui()
102102

103+
def get_header_title(self) -> str:
104+
"""Return the wizard header title for Step 1."""
105+
return "Clinical Programming Session Setup"
106+
103107
def _is_single_grouped_directional(self, cathode_labels: list[str], canvas) -> bool:
104108
"""Check if a single cathode label represents a grouped directional contact."""
105109
if len(cathode_labels) != 1 or not canvas or not canvas.model:
@@ -235,8 +239,6 @@ def _create_settings_group(self) -> QGroupBox:
235239
edit_programs_btn.clicked.connect(self._edit_program_names)
236240
group_row_layout.addWidget(edit_programs_btn)
237241

238-
group_row_layout.addStretch()
239-
240242
group_row.setLayout(group_row_layout)
241243

242244
freq_limits = STIMULATION_LIMITS["frequency"]
@@ -439,6 +441,7 @@ def _create_settings_group(self) -> QGroupBox:
439441
sidebar_scroll.setFrameShape(QFrame.NoFrame)
440442
sidebar_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
441443
sidebar_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
444+
sidebar_scroll.setMinimumWidth(380)
442445
sidebar_scroll.setWidget(sidebar_widget)
443446

444447
electrodes_layout = QVBoxLayout()
@@ -933,25 +936,6 @@ def _toggle_electrode(self, side: str, checked: bool) -> None:
933936
else:
934937
widget.setGraphicsEffect(None)
935938

936-
def _apply_preset_scales(self, scales: list[str]) -> None:
937-
"""Apply a list of preset scales to the clinical scales container."""
938-
# Remove any existing stretches from container
939-
while self.clinical_scales_container.count():
940-
item = self.clinical_scales_container.takeAt(0)
941-
if item.spacerItem():
942-
# Just remove the stretch, no widget to delete
943-
continue
944-
elif item.widget():
945-
item.widget().deleteLater()
946-
947-
for scale_name in scales:
948-
self._add_clinical_scale_row(
949-
scale_name, with_minus=True, on_remove=self.on_remove_callback
950-
)
951-
952-
self._add_clinical_scale_row("", with_plus=True, on_add=self.on_add_callback)
953-
self.clinical_scales_container.addStretch()
954-
955939
def _create_notes_group(self) -> QGroupBox:
956940
"""Create the initial notes group box."""
957941
gb_notes = QGroupBox("Initial notes")
@@ -1216,12 +1200,19 @@ def _load_existing_file(self, file_path: str) -> None:
12161200

12171201
# Load clinical scales
12181202
block0_scales = []
1219-
# Re-read file to get all scales from the latest initial session
1203+
latest_block_id = initial_rows[max_session_id]["block_id"]
1204+
# Re-read file to get scales from the latest initial block only
12201205
with open(file_path, newline="", encoding="utf-8") as f:
12211206
reader = csv.DictReader(f, delimiter="\t")
12221207
for row in reader:
1208+
try:
1209+
bid = int(float(row.get("block_id", "")))
1210+
sid = int(float(row.get("session_ID", "")))
1211+
except ValueError, TypeError:
1212+
continue
12231213
if (
1224-
row.get("session_ID") == str(max_session_id)
1214+
sid == max_session_id
1215+
and bid == latest_block_id
12251216
and row.get("is_initial") == "1"
12261217
):
12271218
sname = row.get("scale_name", None)
@@ -1231,6 +1222,15 @@ def _load_existing_file(self, file_path: str) -> None:
12311222
(str(sname), "" if sval is None else str(sval))
12321223
)
12331224

1225+
# Deduplicate scales by name (keep last occurrence)
1226+
seen_scales = set()
1227+
deduplicated_scales = []
1228+
for name, value in reversed(block0_scales):
1229+
if name not in seen_scales:
1230+
seen_scales.add(name)
1231+
deduplicated_scales.append((name, value))
1232+
block0_scales = list(reversed(deduplicated_scales))
1233+
12341234
# Load notes
12351235
notes_val = latest_initial.get("notes", None)
12361236
if notes_val not in (None, "") and hasattr(self, "notes_edit"):

src/clinical_dbs_annotator/views/step2_view.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ def get_header_title(self) -> str:
6161
"""Return the wizard header title for Step 2."""
6262
return "Session Scale Configuration"
6363

64-
def refresh_theme_icons(self) -> None:
65-
"""Refresh icons that depend on the current theme (call after theme toggle)."""
66-
btn = self.findChild(QPushButton, "settings_session_scales")
67-
if btn:
68-
btn.setIcon(self._create_settings_icon())
69-
7064
def _setup_ui(self) -> None:
7165
"""Set up the UI layout."""
7266
# Session scales group

src/clinical_dbs_annotator/views/step3_view.py

Lines changed: 73 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def __init__(self, parent_style=None):
9191

9292
def get_header_title(self) -> str:
9393
"""Return the wizard header title for Step 3."""
94-
return self._get_step_title()
94+
return "Programming Session Ongoing"
9595

9696
def _undo_last_entry(self) -> None:
9797
"""Show confirmation dialog and delete the last block_ID entry from TSV."""
@@ -110,65 +110,15 @@ def _undo_last_entry(self) -> None:
110110
def _setup_ui(self) -> None:
111111
"""Set up the UI layout."""
112112

113-
# Left macro-panel: Stimulation params + electrodes
114-
left_container = QGroupBox("Session settings")
115-
left_container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
116-
left_container_layout = QHBoxLayout(left_container)
117-
left_container_layout.setContentsMargins(0, 0, 0, 0)
113+
# Left side: Session settings (params + electrodes)
114+
left_widget = QWidget()
115+
left_layout = QVBoxLayout(left_widget)
116+
left_layout.setContentsMargins(0, 0, 0, 0)
117+
settings_group = self._create_session_settings_group()
118+
left_layout.addWidget(settings_group)
119+
left_widget.setMinimumWidth(500)
118120

119-
params_group = self._create_stimulation_params_group()
120-
121-
# Wrap sidebar in a scroll area like step1_view
122-
sidebar_widget = params_group
123-
sidebar_scroll = QScrollArea()
124-
sidebar_scroll.setStyleSheet("""
125-
QScrollArea {
126-
background: transparent;
127-
border: none;
128-
}
129-
QScrollArea > QWidget > QWidget {
130-
background: transparent;
131-
}
132-
""")
133-
sidebar_scroll.setWidgetResizable(True)
134-
sidebar_scroll.setFrameShape(QFrame.NoFrame)
135-
sidebar_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
136-
sidebar_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
137-
sidebar_scroll.setWidget(sidebar_widget)
138-
139-
left_container_layout.addWidget(sidebar_scroll, 1)
140-
141-
electrodes_layout = QVBoxLayout()
142-
electrodes_row = QHBoxLayout()
143-
144-
self.left_canvas_group = QGroupBox("Left electrode")
145-
self.left_canvas_group.setCheckable(True)
146-
self.left_canvas_group.setChecked(True)
147-
self.left_canvas_group.toggled.connect(
148-
lambda checked: self._toggle_electrode("left", checked)
149-
)
150-
left_canvas_layout = QVBoxLayout()
151-
left_canvas_layout.addWidget(self.left_canvas, 1)
152-
self.left_canvas_group.setLayout(left_canvas_layout)
153-
154-
self.right_canvas_group = QGroupBox("Right electrode")
155-
self.right_canvas_group.setCheckable(True)
156-
self.right_canvas_group.setChecked(True)
157-
self.right_canvas_group.toggled.connect(
158-
lambda checked: self._toggle_electrode("right", checked)
159-
)
160-
right_canvas_layout = QVBoxLayout()
161-
right_canvas_layout.addWidget(self.right_canvas, 1)
162-
self.right_canvas_group.setLayout(right_canvas_layout)
163-
164-
electrodes_row.addWidget(self.left_canvas_group, 1)
165-
electrodes_row.addWidget(self.right_canvas_group, 1)
166-
167-
electrodes_layout.addLayout(electrodes_row)
168-
electrodes_layout.addLayout(self._create_electrode_legend_layout())
169-
left_container_layout.addLayout(electrodes_layout, 2)
170-
171-
# Right macro-panel: Scales and notes
121+
# Right side: Scales and notes
172122
right_widget = QWidget()
173123
right_layout = QVBoxLayout(right_widget)
174124
right_layout.setContentsMargins(0, 0, 0, 0)
@@ -177,20 +127,17 @@ def _setup_ui(self) -> None:
177127
right_layout.addWidget(create_horizontal_line())
178128
notes_group = self._create_session_notes_group()
179129
right_layout.addWidget(notes_group)
180-
181-
# left_container.setMinimumWidth(500)
182130
right_widget.setMinimumWidth(400)
183131

184132
# Splitter: right panel shrinks first (stretch=1), left stays stable (stretch=0)
185133
splitter = QSplitter(Qt.Horizontal)
186-
splitter.addWidget(left_container)
134+
splitter.addWidget(left_widget)
187135
splitter.addWidget(right_widget)
188136
splitter.setStretchFactor(0, 0)
189137
splitter.setStretchFactor(1, 1)
190138
splitter.setChildrenCollapsible(False)
191139

192140
self.main_layout.addWidget(splitter)
193-
# self.main_layout.addStretch(1)
194141

195142
self.undo_button = QPushButton("Undo")
196143
self.undo_button.setIcon(
@@ -231,12 +178,14 @@ def _setup_ui(self) -> None:
231178
# Set menu to button
232179
self.export_button.setMenu(self.export_menu)
233180

234-
def _create_stimulation_params_group(self) -> QWidget:
235-
"""Create the stimulation parameters container."""
236-
container = QWidget()
237-
container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
238-
# container.setMinimumWidth(380)
239-
sidebar_layout = QVBoxLayout(container)
181+
def _create_session_settings_group(self) -> QGroupBox:
182+
"""Create the session settings group box."""
183+
gb_session = QGroupBox("Session settings")
184+
gb_session.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
185+
186+
container_layout = QHBoxLayout()
187+
188+
sidebar_layout = QVBoxLayout()
240189

241190
group_row = QGroupBox("Program")
242191
group_row_layout = QHBoxLayout()
@@ -262,8 +211,6 @@ def _create_stimulation_params_group(self) -> QWidget:
262211
edit_programs_btn.clicked.connect(self._edit_program_names)
263212
group_row_layout.addWidget(edit_programs_btn)
264213

265-
group_row_layout.addStretch()
266-
267214
group_row.setLayout(group_row_layout)
268215

269216
freq_limits = STIMULATION_LIMITS["frequency"]
@@ -447,7 +394,61 @@ def _create_stimulation_params_group(self) -> QWidget:
447394
sidebar_layout.addWidget(self.right_group)
448395
sidebar_layout.addStretch(1)
449396

450-
return container
397+
sidebar_widget = QWidget()
398+
sidebar_widget.setLayout(sidebar_layout)
399+
sidebar_scroll = QScrollArea()
400+
sidebar_scroll.setStyleSheet("""
401+
QScrollArea {
402+
background: transparent;
403+
border: none;
404+
}
405+
QScrollArea > QWidget > QWidget {
406+
background: transparent;
407+
}
408+
""")
409+
sidebar_scroll.setWidgetResizable(True)
410+
sidebar_scroll.setFrameShape(QFrame.NoFrame)
411+
sidebar_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
412+
sidebar_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
413+
sidebar_scroll.setMinimumWidth(380)
414+
sidebar_scroll.setWidget(sidebar_widget)
415+
416+
electrodes_layout = QVBoxLayout()
417+
electrodes_row = QHBoxLayout()
418+
419+
self.left_canvas_group = QGroupBox("Left electrode")
420+
self.left_canvas_group.setCheckable(True)
421+
self.left_canvas_group.setChecked(True)
422+
self.left_canvas_group.toggled.connect(
423+
lambda checked: self._toggle_electrode("left", checked)
424+
)
425+
left_canvas_layout = QVBoxLayout()
426+
left_canvas_layout.addWidget(self.left_canvas, 1)
427+
self.left_canvas_group.setLayout(left_canvas_layout)
428+
429+
self.right_canvas_group = QGroupBox("Right electrode")
430+
self.right_canvas_group.setCheckable(True)
431+
self.right_canvas_group.setChecked(True)
432+
self.right_canvas_group.toggled.connect(
433+
lambda checked: self._toggle_electrode("right", checked)
434+
)
435+
right_canvas_layout = QVBoxLayout()
436+
right_canvas_layout.addWidget(self.right_canvas, 1)
437+
self.right_canvas_group.setLayout(right_canvas_layout)
438+
439+
electrodes_row.addWidget(self.left_canvas_group, 1)
440+
electrodes_row.addWidget(self.right_canvas_group, 1)
441+
442+
electrodes_layout.addLayout(electrodes_row)
443+
electrodes_layout.addLayout(self._create_electrode_legend_layout())
444+
445+
container_layout.addWidget(sidebar_scroll, 0)
446+
container_layout.addLayout(electrodes_layout, 1)
447+
448+
layout = QVBoxLayout(gb_session)
449+
layout.addLayout(container_layout)
450+
451+
return gb_session
451452

452453
def _on_left_canvas_validation(self, is_valid: bool, error_msg: str) -> None:
453454
"""Callback when left electrode canvas validation state changes."""

0 commit comments

Comments
 (0)