feat: live canvas backend switching (Options → Canvas Backend)
Both backends share one SelectionState owned by MainWindow and live side by side in a QStackedWidget — switching is setCurrentWidget, so no widget is destroyed mid-session (tearing a VTK window down leaves dangling make-current callbacks). The choice persists in QSettings. CanvasCapabilities declares per-backend gaps (force diagrams and video export stay PyVista-only, both are documented and greyed out) and the UI gates on capabilities rather than the backend name. The architecture gate now allows the canvas_plotly package.
This commit is contained in:
parent
804bf22f61
commit
9a1baa07c2
9 changed files with 442 additions and 38 deletions
|
|
@ -5,7 +5,7 @@ Pre-alpha SAP2000-style desktop GUI for OpenSeesPy. Python 3.10+; **Windows requ
|
|||
## Install
|
||||
|
||||
```bash
|
||||
pip install -e ".[gui,dev]" # desktop: Qt + PyVista + dev tools
|
||||
pip install -e ".[gui,dev]" # desktop: Qt + PyVista + plotly.js backend + dev tools
|
||||
pip install -e . # headless: core + services only, no Qt (scripts, notebooks, web backends)
|
||||
python -m otko # launch GUI (src/otko/app.py:run)
|
||||
```
|
||||
|
|
@ -19,6 +19,7 @@ Strict one-way MVVM + services: `views → viewmodels → services → core`.
|
|||
- `core/` (entities: `project.py`, `geometry/`, `materials/`, `sections/`, `loads/`, `analysis/`, `catalog/`): stdlib + numpy + pydantic only. **No Qt, no openseespy. Period.**
|
||||
- `services/` (`opensees_runner.py`, `persistence.py`, `results.py`, ...): may use core + h5py + openseespy. **No Qt.**
|
||||
- `views/`: PySide6/pyvistaqt only. **No direct `import openseespy`** — go through a service.
|
||||
- `views/canvas3d/` (**PyVista/VTK**, default) and `views/canvas_plotly/` (plotly.js in a `QWebEngineView`) are two backends for the same central 3D view. Both satisfy the `CanvasBackend` protocol in `views/canvas_base.py`, share one `SelectionState` owned by `MainWindow`, and are swapped live via **Options → Canvas Backend** (persisted in `QSettings` under `canvas/backend`). `MainWindow._activate_canvas` keeps both widgets in a `QStackedWidget` — never destroy a canvas mid-session (VTK leaves dangling make-current callbacks). Backend-specific gaps are declared by `CanvasCapabilities` (e.g. Plotly has no force-diagram overlay or video export yet); gate UI on `canvas.capabilities`, never on the backend name. `canvas_plotly/trace_builder.py` is pure (no Qt, no pyvista) and unit-tested headless.
|
||||
- `viewmodels/` bridges core↔Qt (signals, `QUndoStack`); `commands/` holds `QUndoCommand` subclasses.
|
||||
- Rules: public functions need type hints + docstring; new domain entities go through Pydantic validation; ops >50 ms run off the GUI thread (`AnalysisWorker` in QThread, cancel via `isInterruptionRequested()`, results cross threads as lightweight `ResultsHandle` to HDF5).
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue