summaryrefslogtreecommitdiff
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md47
1 files changed, 44 insertions, 3 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 0a10c22..0fa549d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,6 +1,6 @@
# CLAUDE.md
-Guidance for Claude Code (claude.ai/code) working in this repo.
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Running the app
@@ -14,7 +14,8 @@ No build step. Simulation mode default (no hardware needed).
```bash
pip install PyQt6 pyqtgraph numpy pyserial
-pip install nidaqmx # optional — only for real NI hardware
+pip install nidaqmx # optional — only for real NI hardware
+pip install opencv-python # optional — only for motion capture plugin
```
## Architecture
@@ -61,11 +62,16 @@ Control widgets (left panel) go other direction: UI → `ControlWidget._write()`
| `core/acquisition.py` | `AcquisitionEngine` + `ChannelBuffer` |
| `core/signal_processor.py` | Filter chain + derived/virtual channels |
| `core/profile.py` | `.labdaq` profile save/load |
-| `ui/main_window.py` | Top-level window, toolbar, demo device init |
+| `ui/main_window.py` | Top-level window, toolbar, demo device init, plugin lifecycle |
| `ui/control_panel.py` | Left panel output widgets (`OnOffSwitch`, `MotorControl`, etc.) |
| `ui/strip_chart.py` | Live pyqtgraph chart, config-driven by `LayoutConfig` |
+| `ui/add_device_dialog.py` | Add Device dialog; `_PANELS` dict extended by plugins |
+| `ui/windows/plot_window.py` | Plot Builder: BSP tree, `LayoutCanvas` drag-drop, `LayoutConfig` |
| `ui/windows/` | Floating tool windows (Devices, Signals, Plot, Settings) |
| `ui/style_dark.qss` / `style_light.qss` | Full app theme |
+| `plugins/base_plugin.py` | `LabPlugin` ABC, `PluginAction`, `PluginContext` |
+| `plugins/plugin_manager.py` | Discovery, load/unload, `enabled.json` persistence |
+| `plugins/motion_capture/` | Camera device plugin — adds Camera type to Add Device dialog |
### Arduino firmware
@@ -73,6 +79,41 @@ Firmware embedded as `ARDUINO_FIRMWARE` in `api_layers/arduino_layer.py`. When e
Serial protocol: `A0:3.14,D2:1\n` stream from Arduino; `W:D7:1\n` / `P:D9:128\n` commands from PC.
+### Plot layout — BSP tree
+
+`ui/windows/plot_window.py` stores the subplot arrangement as a binary space-partition tree of plain dicts:
+
+```
+{"kind": "leaf", "pane": <int>}
+{"kind": "hsplit", "ratio": <float>, "first": <node>, "second": <node>} # left/right
+{"kind": "vsplit", "ratio": <float>, "first": <node>, "second": <node>} # top/bottom
+```
+
+Key tree functions (all in `plot_window.py`): `_tree_insert`, `_tree_remove`, `_tree_swap`, `_tree_reindex`, `_tree_equalize_ratios`. `tree_to_grid()` converts the tree to pyqtgraph `addItem(row, col, rowspan, colspan)` coordinates. `_tree_grid_size()` returns the LCM of all split denominators — the minimum grid size that expresses all ratios as integers.
+
+`LayoutCanvas` (also in `plot_window.py`) is the drag-and-drop tile editor. Drop zones detected in `_zone_at()`: outer 1/3 of tile = split (bisect), gap between tiles = squeeze (insert-between), center = swap. `_do_drop()` executes the tree mutation.
+
+### Plugin system
+
+Plugins live in `plugins/<id>/` with a `manifest.json` and entry point module. The plugin directory is added to `sys.path` on load, so intra-plugin imports use bare names (`from tracker import CameraTracker`). Cross-plugin imports use the full path (`from ui.add_device_dialog import _PANELS`).
+
+`PluginContext` passed to `on_load(context)`:
+```python
+context.registry # DeviceRegistry
+context.engine # AcquisitionEngine
+context.processor # SignalProcessor
+context.main_window # MainWindow
+```
+
+Optional hooks a plugin can implement:
+- `get_devices() → list[BaseDevice]` — auto-registered into acquisition engine
+- `get_filter_classes() → dict` — added to `SignalProcessor` filter registry
+- `get_toolbar_actions() → list[PluginAction]` — buttons inserted in main toolbar
+- `get_settings_widget() → QWidget` — shown in Settings → Plugins panel
+- `get_save_state() / apply_save_state(dict)` — persisted in `.labdaq` profiles
+
+**Extending Add Device dialog from a plugin**: `ui/add_device_dialog._PANELS` is a module-level dict `{type_name: (PanelClass, id_prefix)}`. Plugins add/remove entries in `on_load`/`on_unload`. Each panel class needs a `build_device(device_id) → BaseDevice` method.
+
### Adding a new device type
1. Subclass `BaseDevice` in new file under `devices/`