Move time window to per-plot spinbox in control bar

Replaces the single global toolbar spinbox with one QSpinBox per plot,
placed between the '+' button and the trace chips. Each plot has an
independent 1–24 h window; values are persisted in plot_settings.json
under 'time_windows'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 23:55:00 +02:00
co-authored by Claude Sonnet 4.6
parent 02814782bf
commit 7d9d928bb1
+26 -32
View File
@@ -349,25 +349,10 @@ class PlotTab(QWidget):
main_layout.setContentsMargins(4, 4, 4, 4) main_layout.setContentsMargins(4, 4, 4, 4)
main_layout.setSpacing(4) main_layout.setSpacing(4)
# ── toolbar ───────────────────────────────────────────────────────────
tb = QWidget()
tb.setMaximumHeight(32)
tb_row = QHBoxLayout(tb)
tb_row.setContentsMargins(0, 0, 0, 0)
tb_row.setSpacing(6)
tb_row.addWidget(QLabel("Time window:"))
self._tw_spin = QSpinBox()
self._tw_spin.setRange(1, 24)
self._tw_spin.setSuffix(" h")
self._tw_spin.setFixedWidth(72)
self._tw_spin.valueChanged.connect(self._on_time_window_changed)
tb_row.addWidget(self._tw_spin)
tb_row.addStretch()
main_layout.addWidget(tb)
# ── data ────────────────────────────────────────────────────────────── # ── data ──────────────────────────────────────────────────────────────
self._traces: list[list[str]] = [[] for _ in range(self.NUM_PLOTS)] self._tw_spins: list[QSpinBox] = []
self._saved_traces: list[list[str]] = self._load_settings() self._traces: list[list[str]] = [[] for _ in range(self.NUM_PLOTS)]
self._saved_traces, _saved_tw = self._load_settings()
self._series: dict[str, deque] = {} self._series: dict[str, deque] = {}
self._units: dict[str, str] = {} self._units: dict[str, str] = {}
@@ -411,7 +396,16 @@ class PlotTab(QWidget):
add_btn.clicked.connect(lambda checked, idx=i: self._add_trace(idx)) add_btn.clicked.connect(lambda checked, idx=i: self._add_trace(idx))
ctrl_row.addWidget(add_btn) ctrl_row.addWidget(add_btn)
ctrl_row.addSpacing(8) tw_spin = QSpinBox()
tw_spin.setRange(1, 24)
tw_spin.setSuffix(" h")
tw_spin.setFixedWidth(60)
tw_spin.setValue(_saved_tw[i])
tw_spin.valueChanged.connect(lambda _, idx=i: self._on_time_window_changed(idx))
self._tw_spins.append(tw_spin)
ctrl_row.addWidget(tw_spin)
ctrl_row.addSpacing(4)
chip_bar = QHBoxLayout() chip_bar = QHBoxLayout()
chip_bar.setSpacing(4) chip_bar.setSpacing(4)
chip_bar.setContentsMargins(0, 0, 0, 0) chip_bar.setContentsMargins(0, 0, 0, 0)
@@ -558,37 +552,37 @@ class PlotTab(QWidget):
try: try:
_SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True) _SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
_SETTINGS_PATH.write_text(json.dumps({ _SETTINGS_PATH.write_text(json.dumps({
"traces": [list(t) for t in self._traces], "traces": [list(t) for t in self._traces],
"time_window": self._tw_spin.value(), "time_windows": [sp.value() for sp in self._tw_spins],
}, indent=2)) }, indent=2))
except OSError: except OSError:
pass pass
def _load_settings(self) -> list[list[str]]: def _load_settings(self) -> tuple[list[list[str]], list[int]]:
try: try:
data = json.loads(_SETTINGS_PATH.read_text()) data = json.loads(_SETTINGS_PATH.read_text())
saved = data.get("traces", []) saved = data.get("traces", [])
while len(saved) < self.NUM_PLOTS: while len(saved) < self.NUM_PLOTS:
saved.append([]) saved.append([])
tw = int(data.get("time_window", 1)) tws = data.get("time_windows", [])
self._tw_spin.blockSignals(True) while len(tws) < self.NUM_PLOTS:
self._tw_spin.setValue(max(1, min(24, tw))) tws.append(1)
self._tw_spin.blockSignals(False) tws = [max(1, min(24, int(v))) for v in tws[: self.NUM_PLOTS]]
return [list(t) for t in saved[: self.NUM_PLOTS]] return [list(t) for t in saved[: self.NUM_PLOTS]], tws
except (OSError, json.JSONDecodeError, KeyError, AttributeError): except (OSError, json.JSONDecodeError, KeyError):
return [[] for _ in range(self.NUM_PLOTS)] return [[] for _ in range(self.NUM_PLOTS)], [1] * self.NUM_PLOTS
# ── drawing ─────────────────────────────────────────────────────────────── # ── drawing ───────────────────────────────────────────────────────────────
def _on_time_window_changed(self): def _on_time_window_changed(self, plot_idx: int):
self._save_settings() self._save_settings()
self._redraw() self._redraw()
def _redraw(self): def _redraw(self):
now = time.time() now = time.time()
cutoff = now - self._tw_spin.value() * 3600
for i, pw in enumerate(self._plot_widgets): for i, pw in enumerate(self._plot_widgets):
cutoff = now - self._tw_spins[i].value() * 3600
pi = pw.getPlotItem() pi = pw.getPlotItem()
pi.clear() pi.clear()
pi.addItem(self._vlines[i], ignoreBounds=True) pi.addItem(self._vlines[i], ignoreBounds=True)