Viewer2D state ownership
Viewer2D state is intentionally classified before deeper Layout/offscreen refactors. This document records the current ownership model and the intended future separation between runtime state, user preferences/config state, and project/Layout persistent state. The goal is to let future work separate these paths without changing rendering output, project files, Layout JSON, PDF export, print preview, or printing behavior.
Current problem
The current Viewer2D state flow mixes several responsibilities through shared code paths:
- live panel/runtime state, such as the active camera while a user pans or zooms;
- user preferences stored in
ConfigManager, such as default grid, ruler, label, and dark-mode settings; - project/Layout persistent state stored in embedded Layout 2D view definitions;
- temporary Layout preview/capture state used to render embedded 2D views through the existing Viewer2D pipeline.
viewer2d::Viewer2DState, ConfigManager, viewer2d::ScopedViewer2DState, Layout preview capture, Layout rasterization, and editor preferences currently overlap. Some values are temporary runtime/capture values, some should survive between projects as user preferences, and some belong to persistent project/Layout definitions. This document makes those boundaries explicit for future refactors without changing current behavior.
Current state structures
viewer2d::Viewer2DStateis the current bridge snapshot used by both editor capture and embedded Layout 2D view rendering. It groups camera, render-option, and layer state even though those fields do not all have the same long-term owner.layouts::Layout2DViewCameraStatestores the camera/view fields used by an embedded Layout 2D view, including offsets, zoom, viewport dimensions, and selected view.layouts::Layout2DViewRenderOptionsstores rendering choices used by the Viewer2D path, including render mode, dark mode, grid, ruler, labels, and top-fixture inversion. Some of these values are user preferences in the editor and project/Layout state when embedded in a Layout definition.layouts::Layout2DViewLayersstores hidden layers and hidden fixture types for a Layout 2D view. This is transitional because the editor also exposes similar visibility throughConfigManager.layouts::Layout2DViewDefinitionis the project/Layout persistent definition for an embedded Layout 2D view. It owns the frame, camera, render options, layer visibility, draw-frame setting, z-index, and id for that Layout element.viewer2d::CaptureState(...)reads the live panel camera when a panel is available, falls back to camera values inConfigManagerotherwise, and reads render/layer options fromConfigManager.viewer2d::ApplyState(...)currently writes the supplied state intoConfigManagerand optionally refreshes the Viewer2D panels. WhenpersistCameraToConfigis false, the camera is applied to the panel without committing camera values to config.viewer2d::ScopedViewer2DStateis the scoped temporary preview/capture mechanism. It captures the previous Viewer2D state, applies a replacement state, and restores the previous state on scope exit.viewer2d::FromLayoutDefinition(...)converts project/Layout persistent state from aLayout2DViewDefinitioninto the bridgeViewer2DStateused by the current render path.viewer2d::ToLayoutDefinition(...)converts aViewer2DStatesnapshot into project/Layout persistent state, including the supplied Layout frame.viewer2d::CaptureLayoutDefinition(...)captures current editor state and converts it into aLayout2DViewDefinitionwhen the user is creating or updating an embedded Layout 2D view.
Ownership classification
| Ownership category | Current fields and examples | Current persistence expectation |
|---|---|---|
| Runtime state | Active live panel camera while the user pans/zooms, transient viewport dimensions, temporary capture framebuffer override, temporary offscreen capture state, repaint/render scheduling flags, capture-in-progress flags, command-buffer capture metadata, render overrides used only for capture, hover/drag/selection overlay state | Runtime-only values must not be serialized into Layout definitions or saved to user configuration unless an explicit editor action owns that persistence. |
| User preferences/config state | Default Viewer2D dark mode, grid visibility/style/color, ruler visibility/color, label display preferences, label font sizes and offsets, fixture label defaults, render mode defaults, top-fixture inversion defaults, general editor preferences that should survive between projects | User preferences/config state belongs to ConfigManager and should survive application sessions, but should not be overwritten by project restore unless the value is explicitly project-owned. |
| Project/Layout persistent state | Layout2DViewDefinition::frame, stored camera for an embedded Layout 2D view, render options stored in a Layout definition, hidden layers or hidden fixture types stored as part of a Layout 2D view, draw-frame and z-index information, the Layout 2D view id |
Project/Layout persistent state belongs to the project/Layout model and may be serialized only through the existing Layout/project save paths. |
| Ambiguous/transitional state | Hidden layers currently exposed through ConfigManager, view2d_dark_mode currently preserved during project load as a user preference, forceBottomViewForTopFixtures which may come from config or a Layout definition depending on context |
Future refactors should resolve these one at a time with compatibility notes and should not change project file or Layout JSON formats accidentally. |
Rules for future refactors
- Temporary Layout preview capture must not permanently mutate user Viewer2D preferences.
- Applying an embedded Layout 2D view for preview must be scoped and restored through
viewer2d::ScopedViewer2DStateor an equivalent scoped temporary Layout preview/capture path. - Project load must not leak the previous project's Layout preview cache, command-buffer cache, persistent RGBA cache, texture state, PBO state, or failure diagnostic state.
- PDF/export/print must not depend on Layout preview texture, PBO, persistent RGBA cache, or failure diagnostic state.
- Runtime-only fields must not be serialized into Layout definitions unless explicitly intended and documented as project/Layout persistent state.
- User preferences should not be overwritten by project restore unless the value is explicitly project-owned.
- Future FBO/offscreen cleanup should stay separate from state ownership cleanup. Replacing or reducing the hidden wx offscreen host is a rendering-target task, not a reason to merge runtime, config, and project/Layout ownership.