diff --git a/gui/plot_tab.py b/gui/plot_tab.py index cb5353d..3f7f395 100644 --- a/gui/plot_tab.py +++ b/gui/plot_tab.py @@ -38,7 +38,7 @@ class PlotTab(QWidget): frame.setFrameShadow(QFrame.Raised) fl = QVBoxLayout(frame) fl.setContentsMargins(2, 2, 2, 2) - pw = SinglePlotWidget(model) + pw = SinglePlotWidget(model, plot_index=i) pw.setMinimumHeight(230) fl.addWidget(pw) grid.addWidget(frame, i // 2, i % 2) diff --git a/gui/plot_widget.py b/gui/plot_widget.py index 031c555..0398f4f 100644 --- a/gui/plot_widget.py +++ b/gui/plot_widget.py @@ -1,8 +1,24 @@ -import sys, os, math, time +import sys, os, math, time, json from datetime import datetime from queue import Queue, Empty from collections import deque +_SETTINGS_PATH = os.path.expanduser('~/.nmea_client_plots.json') + +def _load_plot_settings() -> list: + try: + with open(_SETTINGS_PATH) as f: + return json.load(f).get('plots', []) + except Exception: + return [] + +def _save_plot_settings(settings: list): + try: + with open(_SETTINGS_PATH, 'w') as f: + json.dump({'plots': settings}, f, indent=2) + except Exception: + pass + _root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) _gui = os.path.dirname(os.path.abspath(__file__)) for _p in [_root, _gui]: @@ -256,13 +272,16 @@ class _Canvas(QWidget): # ── Single configurable plot ────────────────────────────────────────────────── class SinglePlotWidget(QWidget): - def __init__(self, model: ReceiverManager): + def __init__(self, model: ReceiverManager, plot_index: int = 0): super().__init__() - self._model = model + self._model = model + self._plot_index = plot_index self._data: dict = {} # rid → [deque(ts), deque(val)] self._known_sats: dict = {} # rid → set[sat_label] (selected only) + self._restore_sat = '' # persisted satellite, applied on first combo fill self._build_ui() + self._load_settings() self._thread = PlotRenderThread() self._thread.frame_ready.connect(self._canvas.set_image) @@ -296,7 +315,7 @@ class SinglePlotWidget(QWidget): bar.addWidget(QLabel("Satellit:")) self._val_cb = QComboBox() self._val_cb.setMinimumWidth(90); self._val_cb.setMaximumWidth(120) - self._val_cb.currentTextChanged.connect(self._submit_render) + self._val_cb.currentTextChanged.connect(self._on_sat_changed) bar.addWidget(self._val_cb) bar.addWidget(QLabel("Quelle:")) @@ -332,9 +351,39 @@ class SinglePlotWidget(QWidget): result.append(it.data(Qt.UserRole)) return result + # ── Persistence ─────────────────────────────────────────────────────────── + + def _load_settings(self): + all_s = _load_plot_settings() + s = all_s[self._plot_index] if self._plot_index < len(all_s) else {} + if 'y_axis' in s: + self._y_cb.blockSignals(True) + self._y_cb.setCurrentText(s['y_axis']) + self._y_cb.blockSignals(False) + self._val_cb.setEnabled(s['y_axis'] != 'pDOP') + if 'history' in s: + self._hist_spin.blockSignals(True) + self._hist_spin.setValue(s['history']) + self._hist_spin.blockSignals(False) + if 'satellite' in s: + self._restore_sat = s['satellite'] + + def _save_settings(self): + all_s = _load_plot_settings() + while len(all_s) <= self._plot_index: + all_s.append({}) + all_s[self._plot_index] = { + 'y_axis': self._y_cb.currentText(), + 'satellite': self._val_cb.currentText(), + 'history': self._hist_spin.value(), + } + _save_plot_settings(all_s) + + # ── Source helpers ──────────────────────────────────────────────────────── + def _rebuild_val_combo(self): selected = set(self._selected_rids()) - current = self._val_cb.currentText() + current = self._val_cb.currentText() or self._restore_sat self._val_cb.blockSignals(True) self._val_cb.clear() sats = set() @@ -344,6 +393,7 @@ class SinglePlotWidget(QWidget): self._val_cb.addItem(s) if current in sats: self._val_cb.setCurrentText(current) + self._restore_sat = '' self._val_cb.blockSignals(False) # ── Render submission ───────────────────────────────────────────────────── @@ -369,12 +419,17 @@ class SinglePlotWidget(QWidget): # ── Config change handlers ──────────────────────────────────────────────── + def _on_sat_changed(self, _text: str): + self._save_settings() + self._submit_render() + def _on_y_changed(self, _text: str): is_pdop = (_text == 'pDOP') self._val_cb.setEnabled(not is_pdop) for rid in list(self._data): n = self._hist_spin.value() self._data[rid] = [deque(maxlen=n), deque(maxlen=n)] + self._save_settings() self._submit_render() def _on_source_changed(self): @@ -385,6 +440,7 @@ class SinglePlotWidget(QWidget): for rid in list(self._data): old_ts, old_v = self._data[rid] self._data[rid] = [deque(old_ts, maxlen=n), deque(old_v, maxlen=n)] + self._save_settings() self._submit_render() # ── Model signals ─────────────────────────────────────────────────────────