diff options
Diffstat (limited to 'plugins/motion_capture/plugin.py')
| -rw-r--r-- | plugins/motion_capture/plugin.py | 84 |
1 files changed, 82 insertions, 2 deletions
diff --git a/plugins/motion_capture/plugin.py b/plugins/motion_capture/plugin.py index 6eb5508..0b44cb4 100644 --- a/plugins/motion_capture/plugin.py +++ b/plugins/motion_capture/plugin.py @@ -18,7 +18,9 @@ Install OpenCV for real camera support: from __future__ import annotations -from plugins.base_plugin import LabPlugin, PluginContext +from typing import List, Optional + +from plugins.base_plugin import LabPlugin, PluginAction, PluginContext class MotionCapturePlugin(LabPlugin): @@ -47,17 +49,95 @@ class MotionCapturePlugin(LabPlugin): # ── Lifecycle ───────────────────────────────────────────────────────── def on_load(self, context: PluginContext) -> None: - self._ctx = context + self._ctx = context + self._btn = None # toolbar button reference + self._windows: dict = {} # device_id → MotionCaptureWindow from ui.add_device_dialog import _PANELS from camera_panel import CameraPanel _PANELS["Camera"] = (CameraPanel, "cam") def on_unload(self) -> None: + for win in list(self._windows.values()): + win.close() + self._windows.clear() from ui.add_device_dialog import _PANELS _PANELS.pop("Camera", None) # ── Integration hooks ───────────────────────────────────────────────── + def get_toolbar_actions(self) -> list: + return [PluginAction( + label="Motion Capture", + icon="🎥", + tooltip="Open camera tracking view", + checkable=True, + callback=self._on_btn_toggled, + button_ref_callback=lambda btn: setattr(self, "_btn", btn), + )] + def get_filter_classes(self) -> dict: from filter import PixelToMMFilter return {"pixel_to_mm": PixelToMMFilter} + + # ── Internal ────────────────────────────────────────────────────────── + + def _camera_devices(self) -> list: + from device import CameraDevice + return [d for d in self._ctx.registry.all_instances() + if isinstance(d, CameraDevice)] + + def _on_btn_toggled(self, checked: bool) -> None: + from PyQt6.QtWidgets import QInputDialog, QMessageBox + if not checked: + return + + cameras = self._camera_devices() + + if not cameras: + QMessageBox.information( + None, "No Camera Devices", + "Add a Camera device first via Devices → Add Device.", + ) + if self._btn is not None: + self._btn.setChecked(False) + return + + if len(cameras) == 1: + self._open_window(cameras[0]) + else: + names = [f"{d.info.name} ({d.info.device_id})" for d in cameras] + choice, ok = QInputDialog.getItem( + None, "Select Camera", "Open tracking view for:", names, 0, False, + ) + if not ok: + if self._btn is not None: + self._btn.setChecked(False) + return + idx = names.index(choice) + self._open_window(cameras[idx]) + + def _open_window(self, device) -> None: + from window import MotionCaptureWindow + dev_id = device.info.device_id + if dev_id in self._windows: + win = self._windows[dev_id] + win.show(); win.raise_() + return + if device._tracker is None: + from PyQt6.QtWidgets import QMessageBox + QMessageBox.warning( + None, "Camera Not Connected", + f"{device.info.name} is not connected. Connect it first.", + ) + if self._btn is not None: + self._btn.setChecked(False) + return + win = MotionCaptureWindow(device._tracker) + win.closed.connect(lambda: self._close_window(dev_id)) + self._windows[dev_id] = win + win.show() + + def _close_window(self, dev_id: str) -> None: + self._windows.pop(dev_id, None) + if not self._windows and self._btn is not None: + self._btn.setChecked(False) |
