#!/usr/bin/env python3 """ GNSS Sky Plot Viewer Unterstützt UBX über serielle Schnittstelle UND TCP/IP (Ser2net). TCP/IP-Verbindungen werden in einer persistenten LRU-Liste (max. 5) gespeichert. """ import sys from PyQt5.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QStatusBar, QSplitter, QTabWidget) from PyQt5.QtCore import Qt from connection_panel import ConnectionPanel from gnss_thread import GnssReader from sat_table import SatelliteTable from sky_plot_widget import SkyPlotWidget from plot_tab import PlotTab # --------------------------------------------------------------------------- # Hauptfenster # --------------------------------------------------------------------------- class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("GNSS Sky Plot – UBX | Seriell + TCP/IP") self.resize(980, 680) self.setStyleSheet("background-color: #12192b; color: #cccccc;") self._reader = None self._build_ui() def _build_ui(self): central = QWidget() self.setCentralWidget(central) root = QVBoxLayout(central) root.setContentsMargins(8, 8, 8, 8) # Haupt-Tabs self._main_tabs = QTabWidget() self._main_tabs.setStyleSheet(""" QTabBar::tab { background: #1a3a5c; color: #cccccc; padding: 6px 20px; border-radius: 3px; } QTabBar::tab:selected { background: #2a5a8c; color: #ffffff; } """) # ── Tab 1: Verbindung ───────────────────────────────────────────────── conn_tab = QWidget() conn_layout = QVBoxLayout(conn_tab) conn_layout.setContentsMargins(8, 8, 8, 8) self._conn_panel = ConnectionPanel() self._conn_panel.connect_requested.connect(self._connect) self._conn_panel.disconnect_requested.connect(self._disconnect) conn_layout.addWidget(self._conn_panel) conn_layout.addStretch() self._main_tabs.addTab(conn_tab, "🔌 Verbindung") # ── Tab 2: Sky View ─────────────────────────────────────────────────── view_tab = QWidget() view_layout = QVBoxLayout(view_tab) view_layout.setContentsMargins(8, 8, 8, 8) # ── Tab 3: Plot ─────────────────────────────────────────────────── self._plot_tab = PlotTab() self._main_tabs.addTab(self._plot_tab, "📈 Plot") # Satellitenanzahl self._sat_label = QLabel("Satelliten: –") self._sat_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self._sat_label.setStyleSheet("font-size: 13px; color: #7ab7d4;") view_layout.addWidget(self._sat_label) # Splitter: Sky Plot | Tabelle splitter = QSplitter(Qt.Horizontal) self._sky_plot = SkyPlotWidget() self._table = SatelliteTable() splitter.addWidget(self._sky_plot) splitter.addWidget(self._table) splitter.setSizes([540, 380]) view_layout.addWidget(splitter) self._main_tabs.addTab(view_tab, "🛰 Sky View") root.addWidget(self._main_tabs) # Status Bar self._status = QStatusBar() self.setStatusBar(self._status) self._status.showMessage("Nicht verbunden.") def __build_ui(self): central = QWidget() self.setCentralWidget(central) root = QVBoxLayout(central) root.setContentsMargins(8, 8, 8, 8) # Obere Leiste top = QHBoxLayout() self._conn_panel = ConnectionPanel() self._conn_panel.connect_requested.connect(self._connect) self._conn_panel.disconnect_requested.connect(self._disconnect) top.addWidget(self._conn_panel) self._sat_label = QLabel("Satelliten: –") self._sat_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self._sat_label.setStyleSheet("font-size: 13px; color: #7ab7d4;") top.addStretch() top.addWidget(self._sat_label) root.addLayout(top) # Splitter: Sky Plot | Tabelle splitter = QSplitter(Qt.Horizontal) self._sky_plot = SkyPlotWidget() self._table = SatelliteTable() splitter.addWidget(self._sky_plot) splitter.addWidget(self._table) splitter.setSizes([540, 380]) root.addWidget(splitter) self._status = QStatusBar() self.setStatusBar(self._status) self._status.showMessage("Nicht verbunden.") def _connect(self, factory, label: str): self._reader = GnssReader(factory) self._reader.satellites_updated.connect(self._on_satellites) self._reader.error_occurred.connect(self._on_error) self._reader.connected.connect( lambda msg: ( self._status.showMessage(f"{msg}: {label}"), self._main_tabs.setCurrentIndex(1), # → Sky View ) ) self._reader.start() self._conn_panel.set_connected(True) self._status.showMessage(f"Verbinde mit {label} …") def __connect(self, factory, label: str): self._reader = GnssReader(factory) self._reader.satellites_updated.connect(self._on_satellites) self._reader.error_occurred.connect(self._on_error) self._reader.connected.connect( lambda msg: self._status.showMessage(f"{msg}: {label}") ) self._reader.start() self._conn_panel.set_connected(True) self._status.showMessage(f"Verbinde mit {label} …") def _disconnect(self): if self._reader: self._reader.stop() self._reader = None self._conn_panel.set_connected(False) self._status.showMessage("Verbindung getrennt.") def _on_satellites(self, sats: list): visible = [s for s in sats if s["elev"] >= 0] used = sum(1 for s in sats if s["used"]) self._sat_label.setText(f"Satelliten: {len(visible)} sichtbar, {used} genutzt") self._sky_plot.update_satellites(visible) self._table.update_satellites(visible) self._plot_tab.update_data(visible) # ← neu def _on_error(self, msg: str): self._status.showMessage(f"Fehler: {msg}") self._disconnect() def closeEvent(self, event): self._disconnect() super().closeEvent(event) # --------------------------------------------------------------------------- if __name__ == "__main__": app = QApplication(sys.argv) app.setStyle("Fusion") win = MainWindow() win.show() sys.exit(app.exec_())