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
+23 -29
View File
@@ -349,25 +349,10 @@ class PlotTab(QWidget):
main_layout.setContentsMargins(4, 4, 4, 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 ──────────────────────────────────────────────────────────────
self._tw_spins: list[QSpinBox] = []
self._traces: list[list[str]] = [[] for _ in range(self.NUM_PLOTS)]
self._saved_traces: list[list[str]] = self._load_settings()
self._saved_traces, _saved_tw = self._load_settings()
self._series: dict[str, deque] = {}
self._units: dict[str, str] = {}
@@ -411,7 +396,16 @@ class PlotTab(QWidget):
add_btn.clicked.connect(lambda checked, idx=i: self._add_trace(idx))
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.setSpacing(4)
chip_bar.setContentsMargins(0, 0, 0, 0)
@@ -559,36 +553,36 @@ class PlotTab(QWidget):
_SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
_SETTINGS_PATH.write_text(json.dumps({
"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))
except OSError:
pass
def _load_settings(self) -> list[list[str]]:
def _load_settings(self) -> tuple[list[list[str]], list[int]]:
try:
data = json.loads(_SETTINGS_PATH.read_text())
saved = data.get("traces", [])
while len(saved) < self.NUM_PLOTS:
saved.append([])
tw = int(data.get("time_window", 1))
self._tw_spin.blockSignals(True)
self._tw_spin.setValue(max(1, min(24, tw)))
self._tw_spin.blockSignals(False)
return [list(t) for t in saved[: self.NUM_PLOTS]]
except (OSError, json.JSONDecodeError, KeyError, AttributeError):
return [[] for _ in range(self.NUM_PLOTS)]
tws = data.get("time_windows", [])
while len(tws) < self.NUM_PLOTS:
tws.append(1)
tws = [max(1, min(24, int(v))) for v in tws[: self.NUM_PLOTS]]
return [list(t) for t in saved[: self.NUM_PLOTS]], tws
except (OSError, json.JSONDecodeError, KeyError):
return [[] for _ in range(self.NUM_PLOTS)], [1] * self.NUM_PLOTS
# ── drawing ───────────────────────────────────────────────────────────────
def _on_time_window_changed(self):
def _on_time_window_changed(self, plot_idx: int):
self._save_settings()
self._redraw()
def _redraw(self):
now = time.time()
cutoff = now - self._tw_spin.value() * 3600
for i, pw in enumerate(self._plot_widgets):
cutoff = now - self._tw_spins[i].value() * 3600
pi = pw.getPlotItem()
pi.clear()
pi.addItem(self._vlines[i], ignoreBounds=True)