summaryrefslogtreecommitdiff
path: root/ui/windows/settings_window.py
AgeCommit message (Collapse)Author
2026-08-01Rename LabDAQ → LabUI and overhaul plugin systemChristian Kolset
Branding: - Rename app, window title, file extension (.labdaq → .labui), user data dirs (~/.labui/), spec file (labdaq.spec → labui.spec), and APP_NAME throughout all source, docs, and config files Plugin system: - Plugins no longer bundled in the PyInstaller build — installed at runtime by users via Settings → Plugins → Install Plugin (zip) - PluginManager now takes user_dir + extra_scan_dirs; user plugins live in ~/.labui/plugins/, dev scan additionally covers project plugins/ - install_from_zip / uninstall / is_user_installed added to PluginManager - vendor/ dir inside plugin zips: prepended to sys.path at load time so plugins can ship their own deps without requiring pip on end-user machine - source_url field in manifest.json: shown as Download button in the missing-plugins dialog when a profile requires an absent plugin - Frozen-app pip install now targets ~/.labui/plugin_packages/ using a real system Python (sys.executable is the exe in frozen builds) Profile loading: - Profile now stores plugins_manifest snapshot (id, name, version, source_url) alongside plugins_enabled - On load, missing or dep-broken plugins trigger MissingPluginsDialog before the rest of the profile is applied; user can install from zip or download via source_url in-dialog, or cancel the load - Plugin reconciliation only enables installed plugins — missing ones are not written to enabled.json UI: - Version label added to status bar (bottom-right, muted colour) - Settings → Plugins tab: Install Plugin… button, per-plugin Remove button for user-installed plugins, live list refresh after install/remove Docs: - New docs/building.md covers the full release pipeline - docs/plugin-development.md updated for new install flow, vendoring, source_url, profile behaviour, and distribution instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-31Add PyInstaller packaging and tufup-based auto-update pipelineChristian Kolset
Full pipeline, verified end-to-end against the real installed tufup 0.10.0 API (initial docs/summaries turned out inaccurate in places — e.g. the apply method is download_and_apply_update, not update; confirmed by inspecting installed package source directly rather than trusting docs alone): - core/version.py: single-source app version constant. - labdaq.spec: PyInstaller onedir build (must be onedir, not onefile — tufup replaces individual files in the install dir on update). Bundles ui/*.qss, plugins/ (needed for runtime plugin discovery), and repository/metadata/root.json once repo_init.py has produced one. Built and smoke-tested: the frozen exe launches and stays running. - scripts/release/{repo_init,repo_release}.py: maintainer-run release tooling using tufup.repo.Repository, manual local signing (keys never touch CI). Both actually run end-to-end during development of this feature against a real build, not just written and assumed correct. Longer expiration_days than tufup-example's CI-oriented defaults (targets/snapshot/timestamp 90d instead of 7d/7d/1d), since we're signing manually, not on an automated daily schedule — see scripts/release/README.md for the re-signing cadence this still requires even between releases. - core/updater.py: thin Client wrapper. Refuses to run outside a frozen build (getattr(sys, "frozen", False)) since there's no installed bundle for tufup to update in `python main.py` dev mode. Bootstraps the bundled root.json into the metadata cache dir on first run — tuf.ngclient.Updater loads root.json from local disk on construction, it does not fetch it remotely by design (the root of trust can't come from the same server being verified). - core/app_settings.py: factored out app_data_dir() (was inline in _settings_path()) so the updater's metadata/target cache dirs live in the same per-user location as settings.json, deliberately outside the install directory an update can replace/move. - Settings > General: version display + "Check for Updates" button, manual-only per discussion (no silent background network calls or surprise restarts for a lab-instrument-control app). Metadata/targets are hosted on this repo's "updates" GitHub Release — a fixed tag, not a normal per-version tag, because TUF's top-level metadata needs a stable URL across app versions. No such GitHub-Releases- hosting example exists in tufup or tufup-example; verified this by fetching tufup-example's actual GitHub Actions workflow file directly after a web search wrongly suggested one existed — the design here is ours, not copied from upstream. Not yet done, deliberately left for the user: running repo_init.py for real (generates production signing keys), and creating the actual "updates" GitHub Release. Both are irreversible-ish, security-sensitive, externally-visible actions outside what should happen without the user directly driving them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29Merge branch 'feat/plugin-pip-install-prompt'Christian Kolset
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-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-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 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-20V8Christian Kolset