Expand description
The MULTI-DOCUMENT model — the app holds N open models, exactly ONE of which is active.
Before this, the shell owned a single EngineState and the document’s
IDENTITY (its store name + the clean baseline the dirty flag compares
against) lived on the file dialog. That pairing is what a document IS, so it
moves here: Document = one engine + its identity, Documents = the
open list + the active index.
§Why the accessor lives on Documents and not on BrepApp
Half the shell passes DISJOINT &mut borrows of its own fields in one call
(self.history.show(ui, self.docs.engine_mut(), …), and the whole
DockContext). A BrepApp::engine_mut()
would borrow ALL of self and every one of those sites would stop compiling.
self.docs.engine_mut() borrows only the docs FIELD, so it composes with a
borrow of any other field exactly as self.state used to.
§One runner per document
Each engine installs its own history runner (a native thread, or — on wasm — its own web worker), because a runner owns the RESIDENT kernel state for the document it executes: sharing one would make a background document’s reply land against the wrong resident registry. The shell therefore pumps EVERY open document each frame, not just the active one, so a run that outlives a tab switch is applied to the engine that submitted it. The cost is real and deliberately unpaid-for here: N documents means N runner threads/workers and N full scenes in memory. Opening a large assembly in a second tab costs what opening it in a second window would.
§Display settings are the SESSION’s; the workbench is the DOCUMENT’s
Theme / UI scale / colors / wireframe / lod live on EngineState.settings,
so without a rule they would silently become per-tab (change the theme, switch
tabs, watch it flip back). [carry_settings] copies them from the outgoing
engine to the incoming one on every activation, and workbench is EXCLUDED
there: a saved document remembers the workbench it was authored in and
restores it on open, which is what makes the Assembly panes appear when you
switch to an assembly tab and vanish when you switch back to a part.
A BRAND NEW tab is the one place the workbench IS carried — by
Documents::spawn_engine, BEFORE the caller loads anything into the
engine, so a document that declares a workbench still overrides it during
the load and one that does not (a New document, a file saved before the
field existed) simply continues the session you were working in.
Structs§
- Document
- ONE open model: the engine that owns it plus the identity the file lane needs — the store name it was opened from / saved to, and the clean baseline.
- Documents
- Every open document + which one is active. Always holds AT LEAST ONE
document: closing the last tab leaves a fresh untitled one in its place, so
Documents::engine_mutis infallible and the shell never has to render a “no document” state that would be an empty viewport with extra steps.
Constants§
- EMPTY_
DOCUMENT - The empty model a New document starts from.
Type Aliases§
- Engine
Factory - Builds a fresh engine for a new document — the platform runner, the viewcube, and the persisted display settings, all applied before anything is loaded into it. Injected by the shell so tests (which need the SYNCHRONOUS inline runner) can construct documents without a background thread.