summaryrefslogtreecommitdiff
path: root/ui/windows
AgeCommit message (Collapse)Author
2026-07-29Add Developer Mode setting, Debug window, and gate simulate behind itChristian Kolset
New Settings > General > "Developer mode" checkbox (default on, so this repo's simulate-by-default workflow is unaffected out of the box) persisted through the existing core/app_settings.py load/save functions. Exposed to code that can't easily receive the settings dict via core.app_settings.is_developer_mode()/set_developer_mode(), a small in-memory cache MainWindow keeps in sync whenever settings are loaded or applied. Debug window (ui/windows/debug_window.py): minimal first pass per the plan — a live console. core/debug_log.py tees stdout/stderr into a ring buffer + Qt signal (installed once in main.py, before anything prints), so the window shows everything printed since app start, including from background poll threads, not just what's printed while it happens to be open. Its toolbar button is hidden unless developer mode is on. Simulate gating: every device's Simulation Mode checkbox/dropdown is now hidden when developer mode is off — ui/add_device_dialog.py (also covers the motion_capture camera panel, which shares this same checkbox rather than having its own), and the per-device config widgets in analog_input.py, arduino_device.py, digital_io.py, nidaqmx_device.py, serial_device.py. Hiding rather than force-clearing an already-simulating device's state — an existing simulated device keeps working if developer mode is turned off later; the option is just not offered again until it's back on. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-06-09Derived channels: signal display names as vars, auto-update template code, ↵Christian Kolset
None op - Variable names derived from signal display name (e.g. "Acceleration X" → acceleration_x) instead of raw channel ID; all auto-names lowercase with underscores - Template code auto-updates x[0]/x[1] refs to named vars as sources are added/changed; stops updating once user edits the code manually - Derivative wrt-channel mode uses separate template with x[1] substituted to channel var - Added "None" passthrough operation (result = x[0]) - source_names persisted in .labdaq profiles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Fix custom_script execution + add templates for expression/function kindsChristian Kolset
- custom_script now uses exec-style (assign to `result`) matching the built-in templates — previously auto-wrapped in def compute() which had no return statement, causing state and channel vars to silently fail - function kind unchanged: auto-wraps body as def compute(x,t); use return - Add SCRIPT_TEMPLATES for expression, function, custom_script kinds; shown automatically when user switches to a script kind (replacing stale code from previous kind) - New channels default to template when no saved code exists Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Channels: inject variable names as comment in code editor, fix derivative wrtChristian Kolset
- Variable names now appear as a live '# Variables: A0 = x[0] · ...' comment at the top of the code editor (function, custom_script, and built-in read-only templates); updates on every source add/remove/change - Derivative 'With Respect To' channel combo now included in variable list as x[1] when channel mode is selected - _apply() strips the auto-generated comment before saving the script so it doesn't pollute the stored expression Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Channels: live variable-name hint in code editor updates with sourcesChristian Kolset
When sources are added, removed, or changed in the derived channel editor, the code group now shows a live "Variables: A0 = x[0] · encoder = x[1]" hint above the code editor so users know the exact names to use in scripts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Scripting: named signal vars, shared vars dict, control scripts, code templatesChristian Kolset
- Named variables in expressions: source channel IDs injected as Python identifiers alongside x[] (e.g. write `A0 * 2` instead of `x[0] * 2`) - Shared `vars` dict on SignalProcessor accessible from all expressions, functions, and control scripts; persisted in .labdaq profiles - Per-derived-channel `state` dict for persistent computation state in custom scripts - Control widgets gain optional on_action_script (Python snippet with value, vars, channels, math in scope); syntax-checked in editor dialog - Built-in derived kinds (derivative, rms, power, etc.) now show their Python implementation as read-only code previews; "Edit as Custom Script" converts to custom_script kind with template pre-filled Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Channels/Signals UX: rename labels, calibration section, splitter, sig# IDsChristian Kolset
Naming conventions: - Devices window: "Channel ID" column → "Signal ID" - Serial device auto-gen IDs: CH# → sig# (generic, SCPI, Modbus fallbacks) - Channels window physical section: "Physical Channels" → "Signals" - Channels window virtual section: "Virtual Channels" → "Channels" - "Add Virtual" button → "Add Channel" - New derived channel default name: "Virtual Channel #" → "Channel #" Signals panel (ChannelPipelineBlock): - Remove Calibrate header button; add inline Calibration section in body - Remove Math section (Derivative/Integral) entirely - scale_offset excluded from filter dropdown; routed to Calibration section - Existing pipelines: scale_offset loads into Calibration, math filters dropped - _FILTER_KEYS excludes derivative, integral, scale_offset Splitter default position: - Left (Signals) pane initialised to minimum content width via QTimer.singleShot - setStretchFactor(0,0) / (1,1): left stays narrow, right grows on resize Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04Merge plot-builder-layout-feature: layout canvas drag-drop fixesChristian Kolset
2026-06-04Fix split zone detection and canvas-edge squeeze behaviorChristian Kolset
Split zone was unreachable: squeezed between outer squeeze (1/6) and center (1/3), leaving a 1/6-wide band impossible to target reliably. Users hitting the tile edge always triggered squeeze instead of split. - Remove squeeze from inside-tile detection entirely. Split now owns the outer 1/3 of each tile edge — large, easy to target. Center keeps the inner 1/3. Squeeze remains gap-detection only (second pass). - Fix canvas-edge squeeze (no adjacent neighbor): instead of bisecting the edge tile, wrap the entire remaining tree in a new directional split with the dragged tile placed at the outer position, then equalize — all tiles end up equal size. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04Fix layout canvas drag-drop: zone logic, pop-out bug, canvas heightChristian Kolset
- Fix squeeze zone pop-out: _adjacent_tile used self._drag_tile (already None at drop time) to exclude the dragged tile from neighbor candidates. Pass dragged_idx explicitly via exclude_idx param instead. - Swap split/squeeze detection areas: outer 1/6 now triggers squeeze (insert-between), inner 1/6→1/3 band triggers split (bisect target). - Extend squeeze detection to gaps between tiles and canvas edges via a second pass in _zone_at that expands tile rects by _LC_GAP+2 and finds the closest outside edge. Canvas-edge squeeze falls through to bisect. - Dynamic canvas height: sync_panes sets height to max(160, n*(min_tile+gap)+2*gap) so 4+ panes never get crushed below minimum tile size. - Remove _tree_grid_size cap of 12: LCM was truncated prematurely, causing unequal rowspans in the strip chart for 5+ panes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Fix virtual channels not appearing in Plot BuilderChristian Kolset
Root cause: PlotWindow deepcopied _chart._cfg on init, so refresh_channels() operated on a stale copy. Also, when _win_plot was None, _on_derived_changed did nothing to prepare the config for when it opened. Fix: - refresh_channels() now owns the derived-pane sync: adds panes for new virtual channels (updating BSP tree), removes panes for deleted ones - _open_plot always passes current _chart._cfg reference then calls refresh_channels() so derived panes sync on every open - _on_derived_changed syncs cfg reference before calling refresh_channels() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Remove __pycache__ from trackingChristian Kolset
2026-06-03Changed dialog text window from channels to signals for clarityChristian Kolset
2026-06-03Fix horizontal zone detection for wide/short tilesChristian Kolset
_zone_at used absolute pixel distance to pick dominant axis, which always favoured the short (vertical) axis for landscape tiles. Replaced with normalized fraction (dist/dimension), so left/right zones are accessible on wide tiles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Three-zone drop system: squeeze, split, centerChristian Kolset
Zone layout (outer to inner per edge): 0–1/6 squeeze (amber): insert dropped tile between two existing tiles 1/6–1/3 split (blue): bisect the target tile 50/50 1/3–2/3 center (green): swap/move Squeeze behaviour: find the tile adjacent to the target in the drop direction; insert dragged tile to the opposite side of that neighbor so it lands visually between them. Falls back to split when no neighbor exists (edge tile). - _zone_at: returns "squeeze_*"/"split_*"/"center" with dominant-axis selection (nearest edge wins) - _adjacent_tile: finds geometrically adjacent tile by pixel proximity - _do_drop: routes squeeze→insert-at-neighbor, split→bisect, center→swap - paintEvent: amber/blue/green per zone type Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Add center-zone move (swap); restore center drop zoneChristian Kolset
- Edge zones (left/right/top/bottom): split target tile equally - Center zone: swap dragged and target tile positions in BSP tree (tree structure preserved, only leaf pane values exchanged) - Center overlay: green highlight (vs blue for split zones) - _tree_swap: immutable swap of two leaf pane values Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Equalize tile sizes after every BSP tree operationChristian Kolset
After each drag-drop, add, or remove, walk the tree and reset each split's ratio to left_leaves/(left_leaves+right_leaves). This distributes space equally per pane regardless of the prior tree structure. - _tree_equalize_ratios: recomputes all ratios bottom-up by leaf count - _tree_leaf_count: counts leaves in a subtree - _tree_grid_size: uses LCM of split denominators (capped at 12) instead of 2^depth, giving exact integer rowspans for equal distributions - _tree_default: balanced binary tree + equalize (not uneven chain) - Applied in _do_drop, _add_pane, _rm Result: 3 side-by-side panes → equal widths; any mixed layout → equal area. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Replace grid-snap canvas with BSP-tree drag-to-split tilingChristian Kolset
Dragging a tile to the edge (left/right/top/bottom) of another tile splits that tile's space and inserts the dragged tile on that side. Drop zones occupy the outer third of each tile edge; center has no zone. Ghost overlay shows the split target during drag. Data model: LayoutConfig.tree (BSP tree as nested dict). PaneSpec.row/col removed. strip_chart uses tree_to_grid() → rowspan/colspan for pyqtgraph. Backward compat: tree=None falls back to layout_mode stacking path. Example: 3 stacked → drag Tile 3 to left of Tile 1 → Tile 3|Tile 1 on top (side-by-side), Tile 2 spans full bottom. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Add drag-and-snap tiling layout canvas to Plot BuilderChristian Kolset
Replace layout radio buttons (Stacked/Side-by-Side/Grid) with a visual LayoutCanvas widget. Pane tiles snap to grid cells on drag-drop; dropping on an occupied cell swaps positions. Ghost highlight shows snap target during drag. - PaneSpec gains row/col fields (None = unassigned; backward compat preserved) - LayoutConfig gains "free" mode; strip_chart reads explicit positions - PaneBlock loses ▲▼ move buttons; reordering is canvas-only - QSS entries added for layoutTile, layoutTileDragging, layoutCanvasBar Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Make Devices, Channels, Plot windows maximizableChristian Kolset
Remove Qt.WindowType.Tool flag — it suppresses the maximize button. Window now has standard chrome with minimize/maximize/close. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Redesign Channels window: side-by-side layout, picker dialog, collapsible ↵Christian Kolset
virtual blocks Physical channels panel: horizontal splitter (left/right), channel picker dialog replaces dropdown, Filters and Math sections per block, Calibrate button, pipeline-enabled checkbox removed. Virtual channels: collapsible blocks, enable checkbox removed, kind dropdown removed (defaults to expression). Window resized to 1400×820. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Persist settings per-computer; add Reset to Defaults in General tabChristian Kolset
- New core/app_settings.py: load/save settings.json to platform config dir (Windows: %APPDATA%, Linux: ~/.config, macOS: ~/Library/Application Support) - MainWindow loads saved settings on startup, saves on every Apply & Close - Settings survive profile switches and app restarts independently of profiles - Settings > General: Reset to Defaults button with QMessageBox confirmation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Fix derivative sources visibility; code editor monospace + 4-space tabsChristian Kolset
- Always insert one source row for derivative/second_derivative on build - Guard in _on_kind: add row when switching to derivative with no sources - Code editor: monospace font (IBM Plex Mono/Consolas fallback) - Code editor: tab stop = 4 character widths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Rename signals_window.py → channels_window.py; update docstringChristian Kolset
Reflects current design: split Physical/Virtual Channels layout, no tabs, no legacy Signals list as primary UI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Rename virtual channel defaults and Kind labelChristian Kolset
- Default ID: sig_N → CH_VN - Default name: Signal N → Virtual Channel N - Rename "Kind" label to "Operation" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Improve Channels window: split layout + derivative w.r.t. selectorChristian Kolset
- Split PipelineTab into Physical/Virtual sections via QSplitter - Each section has independent scroll area, header, and add controls - Add "With Respect To" control for derivative/second_derivative virtual channels: Time (dy/dt) or Channel (dy/dx) - When Channel selected, x variable picker appears for any physical or derived channel - signal_processor computes dy/dx using channel inputs when deriv_wrt=channel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Sync Channels window with device/channel changesChristian Kolset
- Remove redundant Signals tab from Channels window; PipelineTab is now direct content - PipelineTab removes stale blocks when devices are removed or reconfigured - Devices>Signals tab refreshes automatically on device add/remove/configure - Channel name and unit edits in Devices>Signals propagate live to Channels pipeline block headers; missing blocks auto-added if channel is enabled Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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-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>
2026-04-27Improved arduino interface. Now allowing the user to configure pins on the fly.Christian Kolset
2026-04-24Added difference serial protocolsChristian Kolset
2026-04-22Added derived signal to be sources of other derived signals.Christian Kolset
Fixed derived signal saving profile. Renamed Signals>Pipeline to Signas>Channels and adding/removing channels feature.
2026-04-22Removed calibration feature in signal processing > pipeline.Christian Kolset
2026-04-22Added port scanning for new devices and only shows related backend config linesChristian Kolset
2026-04-22Added feature/create-controlsChristian Kolset
2026-04-21Major update to Output controlChristian Kolset
Including: - Control panel - Change status of simulation after devices creation. - Arduino serial conflict with multiple channels. - Claude instructions. - Update to arduino on board code.
2026-04-21V13Christian Kolset
This version contains the profile feature. Allowins users to save the channels, signals and plots for specific labs.
2026-04-20V9Christian Kolset
2026-04-20V8Christian Kolset