Skip to content

Commit 83d1edc

Browse files
committed
Standardize preview checks & validate camera items
Introduce a helper to detect live previews and replace scattered direct PreviewState checks with it. Add validation for selected detected-camera items (show a warning if invalid). Normalize camera backend id casing when formatting labels. Remove a redundant try/except around cleanup guard reset and always reset _cleanup_done on show. Drop an extra in-place settings assignment in the apply flow and remove a now-unneeded call to _populate_from_settings on show. These changes tidy preview control, improve robustness for camera selection, and unify camera identity handling.
1 parent 6da0e49 commit 83d1edc

1 file changed

Lines changed: 19 additions & 14 deletions

File tree

dlclivegui/gui/camera_config/camera_config_dialog.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,12 @@ def dlc_camera_id(self, value: str | None) -> None:
8787

8888
def showEvent(self, event):
8989
super().showEvent(event)
90-
try:
91-
# Reset cleanup guard so close cleanup runs for each session
92-
self._cleanup_done = False
93-
except Exception:
94-
pass
90+
# Reset cleanup guard so close cleanup runs for each session
91+
self._cleanup_done = False
9592

9693
# Rebuild the working copy from the latest “accepted” settings
9794
self._working_settings = self._multi_camera_settings.model_copy(deep=True)
9895
self._current_edit_index = None
99-
self._populate_from_settings()
10096

10197
# Maintain overlay geometry when resizing
10298
def resizeEvent(self, event):
@@ -301,6 +297,9 @@ def _mark_dirty(*_args):
301297
# -------------------------------
302298
# UI state updates
303299
# -------------------------------
300+
def _is_preview_live(self) -> bool:
301+
return self._preview.state in (PreviewState.ACTIVE, PreviewState.LOADING)
302+
304303
def _set_apply_dirty(self, dirty: bool) -> None:
305304
"""Visually mark Apply Settings button as 'dirty' (pending edits)."""
306305
if dirty:
@@ -391,7 +390,7 @@ def _refresh_camera_labels(self) -> None:
391390

392391
def _format_camera_label(self, cam: CameraSettings, index: int = -1) -> str:
393392
status = "✓" if cam.enabled else "○"
394-
this_id = f"{cam.backend}:{cam.index}"
393+
this_id = f"{(cam.backend or '').lower()}:{cam.index}"
395394
dlc_indicator = " [DLC]" if this_id == self._dlc_camera_id and cam.enabled else ""
396395
return f"{status} {cam.name} [{cam.backend}:{cam.index}]{dlc_indicator}"
397396

@@ -690,7 +689,7 @@ def _on_active_camera_selected(self, row: int) -> None:
690689
return
691690

692691
# Stop any running preview when selection changes
693-
if self._preview.state in (PreviewState.ACTIVE, PreviewState.LOADING):
692+
if self.is_preview_live():
694693
self._stop_preview()
695694

696695
self._current_edit_index = row
@@ -726,6 +725,9 @@ def _add_selected_camera(self) -> None:
726725
return
727726
item = self.available_cameras_list.item(row)
728727
detected = item.data(Qt.ItemDataRole.UserRole)
728+
if not isinstance(detected, DetectedCamera):
729+
QMessageBox.warning(self, "Invalid Selection", "Selected item is not a valid camera.")
730+
return
729731
# make sure this is to lower for comparison against camera_identity_key
730732
backend = (self.backend_combo.currentData() or "opencv").lower()
731733

@@ -765,6 +767,8 @@ def _add_selected_camera(self) -> None:
765767
self._start_probe_for_camera(new_cam)
766768

767769
def _remove_selected_camera(self) -> None:
770+
if self._is_preview_live():
771+
self._stop_preview()
768772
if not self._commit_pending_edits(reason="before removing a camera"):
769773
return
770774
row = self.active_cameras_list.currentRow()
@@ -779,6 +783,8 @@ def _remove_selected_camera(self) -> None:
779783
self._update_button_states()
780784

781785
def _move_camera_up(self) -> None:
786+
if self._is_preview_live():
787+
self._stop_preview()
782788
if not self._commit_pending_edits(reason="before reordering cameras"):
783789
return
784790
row = self.active_cameras_list.currentRow()
@@ -792,6 +798,8 @@ def _move_camera_up(self) -> None:
792798
self._refresh_camera_labels()
793799

794800
def _move_camera_down(self) -> None:
801+
if self._is_preview_live():
802+
self._stop_preview()
795803
if not self._commit_pending_edits(reason="before reordering cameras"):
796804
return
797805
row = self.active_cameras_list.currentRow()
@@ -948,9 +956,6 @@ def _apply_camera_settings(self) -> bool:
948956

949957
diff = CameraSettings.check_diff(current_model, new_model)
950958

951-
self._working_settings.cameras[row] = new_model
952-
self._update_active_list_item(row, new_model)
953-
954959
LOGGER.debug(
955960
"[Apply] backend=%s idx=%s changes=%s",
956961
getattr(new_model, "backend", None),
@@ -1043,7 +1048,7 @@ def _reset_selected_camera(self, *, clear_backend_cache: bool = False) -> None:
10431048
return
10441049

10451050
# Stop preview to avoid fighting an open capture
1046-
if self._preview.state in (PreviewState.ACTIVE, PreviewState.LOADING):
1051+
if self.is_preview_live():
10471052
self._stop_preview()
10481053

10491054
cam = self._working_settings.cameras[row]
@@ -1110,7 +1115,7 @@ def _start_probe_for_camera(self, cam: CameraSettings, *, apply_to_requested: bo
11101115
requested width/height/fps with detected device values.
11111116
"""
11121117
# Don’t probe if preview is active/loading
1113-
if self._preview.state in (PreviewState.ACTIVE, PreviewState.LOADING):
1118+
if self._is_preview_live():
11141119
return
11151120

11161121
# Track probe intent
@@ -1357,7 +1362,7 @@ def _start_preview(self) -> None:
13571362
"""Start camera preview asynchronously (no UI freeze)."""
13581363
if not self._commit_pending_edits(reason="before starting preview"):
13591364
return
1360-
if self._preview.state in (PreviewState.ACTIVE, PreviewState.LOADING):
1365+
if self._is_preview_live():
13611366
return
13621367

13631368
row = self._current_edit_index

0 commit comments

Comments
 (0)