Dedup viewer Qt boilerplate after the split

- One _apply_alignment_result() replaces the five copies of the
  cache-clear / generation-bump / Aligned-View-checkbox dance, and
  _on_manual_alignment_saved/_cleared collapse into a shared
  _manual_alignment_changed.
- QSignalBlocker context managers replace every hand-rolled
  blockSignals(True)/set/blockSignals(False) triple (11 sites).
- _make_dspin() replaces the 11 four-to-seven-line QDoubleSpinBox
  constructions; _axes_extent() replaces the duplicated imshow-extent
  formula; _is_fft_mode() replaces the repeated CH1-mode guard.
- Jobs constants replace the stringly-typed background-job keys.
- The two 160-line widget builders split along their section banners:
  _build_left_panel -> file/info/view/roi groups, the manual-alignment
  _build_ui -> six per-group builders + _connect_controls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Thomas Ales
2026-08-06 10:56:50 -05:00
parent 26a34f7436
commit f0f622b9ab
3 changed files with 172 additions and 186 deletions
+38 -2
View File
@@ -2,8 +2,8 @@
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
QFormLayout, QFrame, QGroupBox, QLabel, QScrollArea, QSizePolicy,
QVBoxLayout, QWidget,
QDoubleSpinBox, QFormLayout, QFrame, QGroupBox, QLabel, QScrollArea,
QSizePolicy, QVBoxLayout, QWidget,
)
from sras_format import CH1_IDX, CH3_IDX, CH4_IDX
@@ -52,6 +52,42 @@ _SPIN_MIN_W = 96
# Small layout helpers
# ---------------------------------------------------------------------------
class Jobs:
"""Keys for SrasViewerWindow's background-job registry (_run_worker /
_job_running) and its progress dialogs — one place instead of string
literals scattered across window and dialogs."""
LOAD = "load"
COMPUTE = "compute"
DC_PRECOMPUTE = "dc_precompute"
BATCH = "batch"
ALIGN = "align"
MANUAL_ALIGN_MASKS = "manual_align_masks"
MANUAL_ALIGN_CORRELATE = "manual_align_correlate"
def _make_dspin(lo: float, hi: float, decimals: int, *, suffix: str = "",
value: float | None = None, step: float | None = None) -> QDoubleSpinBox:
"""A QDoubleSpinBox with the panel-standard construction."""
spin = QDoubleSpinBox()
spin.setRange(lo, hi)
spin.setDecimals(decimals)
if suffix:
spin.setSuffix(suffix)
if step is not None:
spin.setSingleStep(step)
if value is not None:
spin.setValue(value)
spin.setMinimumWidth(_SPIN_MIN_W)
return spin
def _axes_extent(x_axis, y_axis, dx: float, dy: float) -> list[float]:
"""Matplotlib imshow extent with half-pixel margins, Y flipped so row 0
renders at the top."""
return [x_axis[0] - dx / 2, x_axis[-1] + dx / 2,
y_axis[-1] + dy / 2, y_axis[0] - dy / 2]
def _wrap_label(text: str = "", css: str | None = None) -> QLabel:
"""A word-wrapped QLabel that reports its *wrapped* height to the layout.