Onion Skin View Widget Roadmap

OnionSkinViewWidget Development Roadmap

This document tracks remaining development tasks for the Onion Skin View Widget. For documentation of completed features and current architecture, see the main developer documentation.

Completed Work Summary

The following features are complete and documented in index.qmd:

  • Widget skeleton: EditorState pattern, registration, state/view/properties factories
  • State management: OnionSkinViewState with HorizontalAxisState, VerticalAxisState composition; OnionSkinViewStateData serializable struct with rfl::json
  • Three data type support: Add/remove multiple PointData, LineData, and MaskData keys via properties panel
  • Temporal window: Configurable window_behind / window_ahead (frames before/after current time)
  • Alpha curve: Linear, Exponential, Gaussian curves with configurable min/max alpha
  • Rendering pipeline: SceneRenderer for points (glyphs), lines (polylines), and mask contours (polylines), all with per-element temporal alpha
  • Spatial mapping: SpatialMapper::mapPointsInWindow(), mapLinesInWindow(), mapMaskContoursInWindow() for windowed data retrieval
  • Back-to-front rendering: Depth-sorted by temporal distance for correct alpha blending
  • Current-frame highlight: Distinct colors for current-frame elements (orange-red vs blue/green/orange)
  • Auto-fit bounds: Bounding box computation from all windowed point, line, and mask contour data
  • Axis system: HorizontalAxisWidget (X) and VerticalAxisWidget (Y) with bidirectional sync, including the “silent update” pattern
  • Interaction: Separated X/Y zoom, pan via shared PlotInteractionHelpers
  • Entity selection: Click-to-select point at current frame (15px tolerance), double-click for navigation
  • Properties panel: Data key tables + combo boxes for all 3 types, temporal window controls, alpha curve controls, rendering controls (point size, line width, highlight current), axis range controls in collapsible sections
  • DataManager observer: Combo box population (point, line, mask), cleanup in destructor, and stale key purging when data keys are deleted from DataManager; tested in OnionSkinViewPropertiesWidget.test.cpp
  • State serialization: Full round-trip JSON via rfl::json
  • Registration wiring: timeChanged_onTimeChanged(), timePositionSelectedEditorRegistry::setCurrentTime()
  • Per-key line style: Each LineData key has its own CorePlotting::LineStyleData (color, thickness, alpha) stored in OnionSkinViewStateData::line_key_line_styles; managed at runtime via LineStyleState QObject wrappers; editable in a collapsible “Line Style Options” section in the properties panel via LineStyleControls; `alpha` field sets the maximum alpha before temporal decay; serialized/deserialized as part of the JSON state
  • Per-key mask contour style: Each MaskData key has its own CorePlotting::LineStyleData (color, thickness, alpha) stored in OnionSkinViewStateData::mask_key_line_styles; managed at runtime via LineStyleState QObject wrappers; editable in a collapsible “Mask Style Options” section in the properties panel via LineStyleControls; alpha field sets the maximum alpha before temporal decay; serialized/deserialized as part of the JSON state

Not yet implemented: SVG export.

Phase 4: SVG Export

Status: Not started. No export infrastructure exists in the current widget.

Goal: Allow the user to export the current onion skin view as an SVG file, preserving vector quality for publication.

4.1 Export Approach

SVG export requires converting the OpenGL scene to vector graphics. Two approaches:

Option A — Scene-to-SVG serialization (recommended): Walk the RenderableScene primitives (glyphs, polylines) and emit SVG <circle>, <polygon>, and <polyline> elements with the same colors and alpha values computed during rebuildScene(). This avoids OpenGL framebuffer capture and produces clean, resolution-independent output.

Option B — QPainter-based rendering: Use QSvgGenerator + QPainter to re-render the scene data using Qt’s 2D drawing API. This provides more mature vector rendering but requires duplicating the rendering logic outside OpenGL.

4.2 SVG Export Infrastructure

Because SVG export will be needed by multiple widgets (see cross-widget export below), the export logic should be implemented as a shared utility rather than per-widget code:

Component Location Purpose
SvgExporter CorePlotting/Export/ Scene-to-SVG conversion
ExportButton Plots/Common/ Shared “Export SVG” button + file dialog

SVG export is also a planned feature for:

Widget Export Complexity Notes
LinePlotWidget Medium Trial-aligned lines + axes
TemporalProjectionViewWidget Medium Full spatial overlay
OnionSkinViewWidget Medium Windowed spatial + alpha fading

4.3 Export Flow

User clicks "Export SVG" button in properties panel
        ↓
File dialog → choose output path
        ↓
SvgExporter reads current RenderableScene (or re-gathers data from state)
        ↓
For each glyph: emit SVG element with position, size, fill color + opacity
For each polyline: emit SVG <polyline> with stroke color + opacity + width
        ↓
Add axis labels, tick marks, bounds metadata
        ↓
Write SVG file

4.4 Properties Panel Controls

Add an “Export” section to the properties panel:

  • Export SVG button — opens file dialog and triggers export
  • Include axes checkbox — whether to render axis labels and ticks in the SVG
  • Background color — whether to include the dark background or use transparent

Priority Order

Priority Phase Status Dependency
1 Phase 4 — SVG Export Not started Phases 2–3 (export should capture per-key styles)