Skip to content

Persist Area Detector viewer state via ConfigSource (TOML ↔ DB round-trip) #77

Description

@pecomyint

Problem

All Area Detector viewer toggle states — colormap, autoscale, log scale, crosshair, threshold, freeze, display ROIs, transpose, pixel ordering — are hardcoded defaults that reset on every restart. Users lose their preferred view configuration each session.

Scope — Tier 1: Portable Preferences Only

This issue covers semantic viewer preferences that should round-trip through TOML export/import. Machine-local layout state (window geometry, dock positions, last-typed prefix) is handled separately by #85 via QSettings.

See State Persistence Architecture for the full two-tier design.

Decision rule

"Would I want this setting to travel with my TOML config to another machine?"

What to persist (Tier 1)

Key Type Default Description
colormap str "viridis" Selected gradient from color bar context menu
autoscale bool true Auto-scale toggle (5%-95% histogram)
log_scale bool false Logarithmic intensity scale
crosshair_visible bool false Crosshair overlay toggle
threshold_enabled bool false Auto threshold toggle
freeze_image bool false Lock/Freeze image toggle
display_rois bool true ROI overlay visibility
transpose bool false Image transpose
pixel_order str "C" Pixel ordering (C or Fortran)
plotting_frequency int 10 Stats plotting refresh rate

TOML representation

# New section — existing sections unchanged
[viewer_state.area_detector]
colormap = "viridis"
autoscale = true
log_scale = false
crosshair_visible = false
threshold_enabled = false
freeze_image = false
display_rois = true
transpose = false
pixel_order = "C"
plotting_frequency = 10

Implementation

New functions in settings.py

Follow the existing save_detector_prefix() / save_input_channel() pattern:

def load_viewer_state(viewer_key: str = "area_detector") -> dict:
    cfg = ConfigSource(_get_effective_locator()).load()
    return cfg.get("viewer_state", {}).get(viewer_key, {})

def save_viewer_state(viewer_key: str, state: dict) -> bool:
    src = ConfigSource(_get_effective_locator())
    existing = src.load()
    vs = existing.setdefault("viewer_state", {})
    vs[viewer_key] = state
    return src.save({"viewer_state": vs})

Wire into area detector viewer

  • On init: call load_viewer_state("area_detector") to set checkbox/colormap values instead of hardcoded defaults
  • On each toggle change (existing signal handlers like autoscale_checked(), threshold_checked(), etc.): call save_viewer_state() with updated values
  • On closeEvent: bulk save as safety net

The round-trip

  • User imports a TOML (with [viewer_state.area_detector]) → it flows into the local DB profile, viewer opens with those preferences
  • User changes a toggle in the UI → DB profile is updated immediately via ConfigSource.save()
  • User exportsexport_profile_to_toml() includes viewer state, producing a complete portable config
  • User shares the TOML → recipient loads it and gets detector config AND viewer preferences

The database (dashpva.db) stays local and is not shared. The TOML file is the portable artifact.

Acceptance criteria

  • load_viewer_state() and save_viewer_state() added to settings.py
  • Area detector viewer reads initial state from config instead of hardcoded defaults
  • Toggle changes persist through ConfigSource.save() on each state change
  • Viewer state survives application restart
  • TOML export includes [viewer_state.area_detector] section
  • TOML import with viewer state correctly populates the DB profile and UI
  • No changes to ConfigSource internals needed — viewer_state is just another dict key

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

in progressThis issue is currently being worked on

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions