summaryrefslogtreecommitdiff
path: root/ui/main_window.py
diff options
context:
space:
mode:
Diffstat (limited to 'ui/main_window.py')
-rw-r--r--ui/main_window.py36
1 files changed, 35 insertions, 1 deletions
diff --git a/ui/main_window.py b/ui/main_window.py
index ba93121..6dae1be 100644
--- a/ui/main_window.py
+++ b/ui/main_window.py
@@ -12,9 +12,10 @@ from PyQt6.QtWidgets import (
QToolBar, QSizePolicy, QApplication, QFrame,
QAbstractSpinBox, QComboBox, QMenu,
)
-from PyQt6.QtCore import Qt, QTimer, QObject, QEvent, QRect, pyqtSignal, pyqtSlot
+from PyQt6.QtCore import Qt, QTimer, QObject, QEvent, QRect, QByteArray, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QPainter, QColor, QFont, QAction
import logging
+import base64
import os
@@ -116,6 +117,12 @@ _LIGHT_QSS = os.path.join(os.path.dirname(os.path.abspath(__file__)), "style_lig
class MainWindow(QMainWindow):
+ # Bump when dock/toolbar structure changes in a way that would make an
+ # old saved dock_state blob meaningless (e.g. a dock renamed/removed) —
+ # restoreState() rejects a mismatched version and just no-ops instead
+ # of applying garbage.
+ _DOCK_STATE_VERSION = 1
+
def __init__(self):
super().__init__()
self.setWindowTitle("LabUI")
@@ -622,6 +629,7 @@ class MainWindow(QMainWindow):
def _profile_capture(self, name: str = "Profile") -> Profile:
"""Serialise current state into a Profile object."""
+ self._capture_dock_state()
return ProfileManager.capture(
registry=self.registry,
processor=self.processor,
@@ -702,6 +710,7 @@ class MainWindow(QMainWindow):
self._win_config.refresh_devices()
self._win_config.refresh_derived()
self._win_config.refresh_plot(self._chart._cfg)
+ QTimer.singleShot(0, self._apply_dock_state)
self._status.setText(f"Profile loaded: {profile.name}")
# ── Device / signal events ────────────────────────────────────────────
@@ -819,6 +828,31 @@ class MainWindow(QMainWindow):
self._apply_theme(self._settings.get("theme", "dark"))
self.engine._interval = self._settings.get("poll_ms", 100) / 1000.0
self._apply_developer_mode(self._settings.get("developer_mode", False))
+ QTimer.singleShot(0, self._apply_dock_state)
+
+ def _capture_dock_state(self):
+ """Snapshot Control Panel / Namespace dock area, floating geometry,
+ visibility, size and order via Qt's own QMainWindow.saveState() —
+ one call covers everything a QDockWidget can have moved, instead of
+ hand-tracking each attribute. Stored as base64 in self._settings,
+ which both app_settings.json (save_settings()) and .labui profiles
+ (Profile.settings — see ProfileManager.capture()) already round-trip
+ verbatim, so this needs no schema changes on either side, just
+ needs to run before whichever save happens."""
+ raw = bytes(self.saveState(self._DOCK_STATE_VERSION))
+ self._settings["dock_state"] = base64.b64encode(raw).decode("ascii")
+
+ def _apply_dock_state(self):
+ """Restore saved dock state — deferred one event-loop tick (via
+ QTimer.singleShot(0, ...) at call sites) since restoreState() before
+ the main window's initial layout has settled doesn't stick, the
+ same reason splitter sizing elsewhere in this codebase (e.g.
+ plot_window.py's _init_split) defers similarly."""
+ encoded = self._settings.get("dock_state")
+ if not encoded:
+ return
+ raw = QByteArray(base64.b64decode(encoded))
+ self.restoreState(raw, self._DOCK_STATE_VERSION)
def _apply_developer_mode(self, enabled: bool):
level = logging.DEBUG if enabled else logging.WARNING