summaryrefslogtreecommitdiff
path: root/plugins
AgeCommit message (Collapse)Author
2026-07-29Merge branch 'feat/plugin-pip-install-prompt'Christian Kolset
2026-07-29Check plugin dependencies before loading, warn instead of silent console errorChristian Kolset
manifest.json already had an unused "requires" field (motion_capture's manifest lists opencv-python>=4.8.0) — PluginManifest never parsed it, so a missing dependency just crashed the import inside _load_plugin(), caught by the broad except and only ever printed to the console. Adds PluginManifest.requires, PluginManager.missing_requirements()/ get_missing_dependencies(), and an early check in _load_plugin() that skips the risky import entirely when a requirement is missing. main_window.plugin_enable() now checks this before calling PluginManager.enable() and shows a QMessageBox with the missing packages and a pip install command instead of failing silently. Checks by distribution name via importlib.metadata (what pip installed it as), not import name — those differ for packages like opencv-python (imports as cv2) or pyserial (imports as serial), so importlib.util. find_spec() would give false negatives. Also fixes a button-state bug this surfaces: SettingsWindow's plugin toggle optimistically flipped to "Disable" the instant Enable was clicked, before knowing whether enabling actually succeeds — pre-existing, but now trivially reproducible (any plugin missing a dependency). Enable no longer flips the button immediately; main_window calls the new sync_plugin_button() once the real outcome is known. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29Add editable device display name, persist it across profile save/loadChristian Kolset
DeviceInfo.name existed but was hardcoded per device type and never operator-editable. Adds a Display Name field to Add Device and makes the Info-tab Name field in the device config dialog editable, and threads the name through get_save_config()/ProfileManager.apply() so a custom name survives a .labdaq save/reload instead of reverting to the type default. Name is applied post-construction rather than as a constructor kwarg, since no device factory declares a "name" param. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28Update CML protocol documentation and improve command handling; adjust ↵Christian Kolset
motion_capture setting to false
2026-06-09Motion capture: profile support, FPS config, persistent tracking, window stateChristian Kolset
Profile integration: - CameraDevice.get_save_config() serialises camera_index, simulate, resolution, fps — cameras now persist in .labdaq profiles - ProfileManager.register/unregister_device_factory() lets plugins register their device classes for profile restoration without core → plugin dependency - MotionCapturePlugin registers CameraDevice factory on load/unload Camera configuration: - Add Frame Rate combo to CameraPanel (Default/15/24/30/60/120 fps) defaults to 30 fps; flows through to CAP_PROP_FPS on connect - tracker.start() accepts fps param alongside existing resolution Tracking persistence: - CameraTracker.is_running() — checks thread alive state - MotionCaptureWindow initialises _connected from tracker.is_running() so reopening the window resumes the live feed without restarting the camera or losing the active tracking state Window state: - Plugin saves px_per_mm + camera_idx when window closes - Reopened window restores saved values and syncs mode/shape UI from tracker state via restore_ui_state() (signals blocked to avoid resetting tracker) - Window type changed to Qt.WindowType.Window for independent close button on all Linux WMs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Upgrade motion capture: template matching, frame-freeze selection, resolutionChristian Kolset
Tracking: - Add "template" mode (default) using snapshot + shape-masked matchTemplate - Add "csrt" mode as alternative for texture-rich targets - set_roi_rect(x, y, w, h, frame_rgb) initialises from exact selection rect - set_roi() delegates to set_roi_rect (centred square, backwards-compat) - start() accepts resolution=(w, h) to set camera capture resolution Selection UX: - Replace QLabel feed with FrameSelector widget (custom QWidget) - "Click to Track" freezes frame; user scrolls to zoom (anchored to cursor), right-drags to pan, left-drags to draw rubber-band selection - Shape preview: rectangle or inscribed ellipse depending on mode - "Confirm Selection" extracts template from frozen frame and starts tracking - "Clear" cancels selection or clears active tracking Configuration: - CameraPanel adds Resolution combo (Default / 640×480 / 720p / 1080p / 1440p) - CameraDevice stores and forwards resolution to tracker.start() - Template Match listed first in Mode combo; shape combo hidden for CSRT Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04Restore Motion Capture toolbar button with multi-camera supportChristian Kolset
get_toolbar_actions() returns a checkable 🎥 button. On click: - 0 camera devices → info message, button unchecks - 1 camera device → opens MotionCaptureWindow directly - N camera devices → QInputDialog picker, opens selected device's window Windows tracked per device_id; closing a window removes it from the map and unchecks the button when none remain. on_unload closes all open windows before deregistering the Camera panel. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04Redesign motion capture plugin as Camera device typeChristian Kolset
Plugin now registers a "Camera" option in the Add Device dialog on load (removes it on unload) instead of auto-creating a single device. - camera_panel.py (new): CameraPanel with CameraScanThread that probes OpenCV indices 0–5, lists found cameras with resolution, shows "No cameras detected" when none available, simulation checkbox. build_device() returns CameraDevice for the selected index. - device.py: rewrite MotionCaptureDevice → CameraDevice. Each instance owns its own CameraTracker created in connect(). Status is CONNECTED or SIMULATED based on tracker.simulated. get_config_widget() shows source/status and an "Open Camera View" button that launches the existing MotionCaptureWindow for that device's tracker. Backward-compat alias MotionCaptureDevice = CameraDevice kept for saved profiles. - plugin.py: simplified to on_load/_PANELS registration + pixel_to_mm filter. No auto-devices, no toolbar button, no settings widget. Camera data flows through the standard Device → Signal → Channel → Plot pipeline like any other device. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Remove __pycache__ from trackingChristian Kolset
2026-06-03Fix settings/plugin window bugs; remove example pluginChristian Kolset
- Add missing QGroupBox import to settings_window (caused silent crash on open) - Remove Controls tab and _controls_tab() method from settings - Clamp child window positions to screen bounds so they don't go off-screen on Windows when main window is maximized - Apply same screen-clamp fix to Motion Capture plugin window - Delete example plugin; disable it in enabled.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Motion capture: camera selection dropdownChristian Kolset
Replace camera index spinbox with a combo listing detected cameras by name. On Linux enumerates /dev/video* and reads device names from sysfs (fast, no probing). Fallback probes cv2.VideoCapture indices 0-7 on other platforms. Simulation entry always appended as last option. Also adds explicit simulation mode (index -1) to tracker.start() and a rescan button (⟳) in both the main window and the Settings > Plugins widget. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Added Motion Capture pluginChristian Kolset
Tracks a user-selected point via webcam (OpenCV CSRT tracker) and streams x_pos / y_pos pixel coordinates as live channels into the acquisition pipeline. Falls back to a Lissajous figure simulation when opencv-python is not installed, so the plugin works immediately without hardware. - tracker.py: background thread, real camera + sim modes, thread-safe API - device.py: BaseDevice reading x/y from tracker, wires into engine - filter.py: custom pixel_to_mm filter (registered in FILTER_CLASSES) - window.py: floating tool window, live feed, click-to-track ROI selection - plugin.py: LabPlugin wiring all pieces together, toolbar button, settings widget, profile save/restore Also: PluginAction.button_ref_callback lets plugins store a ref to their toolbar button so they can uncheck it when their window closes. opencv-python install note added to requirements.txt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Added plugin/add-on systemChristian Kolset
Plugins live in plugins/<name>/ with a manifest.json and a LabPlugin subclass. Enabled/disabled in Settings > Plugins tab; state persists in plugins/enabled.json and in .labdaq profiles (loading a profile enables/disables plugins to match). Plugins can contribute toolbar buttons, BaseDevice instances (auto-wired into acquisition pipeline), custom signal filter classes, a settings widget, and profile state via get_save_state/apply_save_state. Load errors now report the exact failing stage (file not found, class missing, on_load crash). Includes example plugin skeleton and docs/plugin-development.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>