gui: add checkable constellation legend to filter sky plot by GNSS system
Replaces the static painted legend with real checkboxes (one per GNSS system, color-swatched to match GNSS_COLORS) so users can toggle which constellations show in the sky plot and satellite table, mirroring the existing receiver-source filter checkboxes.
This commit is contained in:
+34
-4
@@ -13,7 +13,7 @@ from PyQt5.QtWidgets import (
|
|||||||
QSplitter, QGroupBox, QFrame, QCheckBox, QSpinBox,
|
QSplitter, QGroupBox, QFrame, QCheckBox, QSpinBox,
|
||||||
)
|
)
|
||||||
from PyQt5.QtCore import Qt, QTimer
|
from PyQt5.QtCore import Qt, QTimer
|
||||||
from PyQt5.QtGui import QColor, QBrush
|
from PyQt5.QtGui import QColor, QBrush, QIcon, QPixmap
|
||||||
|
|
||||||
from data_model import ReceiverManager, GNSS_NAMES, GNSS_COLORS
|
from data_model import ReceiverManager, GNSS_NAMES, GNSS_COLORS
|
||||||
from sky_widget import SkyPlotWidget
|
from sky_widget import SkyPlotWidget
|
||||||
@@ -37,6 +37,8 @@ class SkyTab(QWidget):
|
|||||||
self._name_labels: dict = {} # rid -> QLabel (receiver display name)
|
self._name_labels: dict = {} # rid -> QLabel (receiver display name)
|
||||||
self._trail: dict = {} # (rid, gnss_id, sv_id) -> deque[(elev, azim)]
|
self._trail: dict = {} # (rid, gnss_id, sv_id) -> deque[(elev, azim)]
|
||||||
self._hi_timers: dict = {} # (rid, gnss_id, sv_id) -> QTimer
|
self._hi_timers: dict = {} # (rid, gnss_id, sv_id) -> QTimer
|
||||||
|
self._gnss_checks: dict = {} # gnss_id -> QCheckBox
|
||||||
|
self._enabled_gnss: set = set(GNSS_NAMES.keys())
|
||||||
|
|
||||||
outer = QVBoxLayout(self)
|
outer = QVBoxLayout(self)
|
||||||
outer.setContentsMargins(4, 4, 4, 4)
|
outer.setContentsMargins(4, 4, 4, 4)
|
||||||
@@ -68,7 +70,28 @@ class SkyTab(QWidget):
|
|||||||
self._trail_spin.setEnabled(False)
|
self._trail_spin.setEnabled(False)
|
||||||
self._trail_spin.valueChanged.connect(self._on_trail_toggled)
|
self._trail_spin.valueChanged.connect(self._on_trail_toggled)
|
||||||
src_bl.addWidget(self._trail_spin)
|
src_bl.addWidget(self._trail_spin)
|
||||||
outer.addWidget(src_box)
|
|
||||||
|
# ── Constellation legend / filter ─────────────────────────────────────
|
||||||
|
const_box = QGroupBox("Constellations (check to show)")
|
||||||
|
const_box.setMaximumHeight(80)
|
||||||
|
const_bl = QHBoxLayout(const_box)
|
||||||
|
const_bl.setContentsMargins(4, 2, 4, 2)
|
||||||
|
const_bl.setSpacing(8)
|
||||||
|
for gid in sorted(GNSS_NAMES):
|
||||||
|
cb = QCheckBox(GNSS_NAMES[gid])
|
||||||
|
cb.setChecked(True)
|
||||||
|
pix = QPixmap(10, 10)
|
||||||
|
pix.fill(QColor(GNSS_COLORS.get(gid, '#9E9E9E')))
|
||||||
|
cb.setIcon(QIcon(pix))
|
||||||
|
cb.toggled.connect(lambda checked, g=gid: self._on_gnss_toggled(g, checked))
|
||||||
|
self._gnss_checks[gid] = cb
|
||||||
|
const_bl.addWidget(cb)
|
||||||
|
const_bl.addStretch()
|
||||||
|
|
||||||
|
filter_row = QHBoxLayout()
|
||||||
|
filter_row.addWidget(src_box)
|
||||||
|
filter_row.addWidget(const_box)
|
||||||
|
outer.addLayout(filter_row)
|
||||||
|
|
||||||
# ── Info bar (one card per receiver) ──────────────────────────────────
|
# ── Info bar (one card per receiver) ──────────────────────────────────
|
||||||
info_frame = QFrame()
|
info_frame = QFrame()
|
||||||
@@ -181,7 +204,7 @@ class SkyTab(QWidget):
|
|||||||
def _visible_sats(self) -> list:
|
def _visible_sats(self) -> list:
|
||||||
selected = self._selected_rids()
|
selected = self._selected_rids()
|
||||||
return [(k[0], self._store[k])
|
return [(k[0], self._store[k])
|
||||||
for k in self._store if k[0] in selected]
|
for k in self._store if k[0] in selected and k[1] in self._enabled_gnss]
|
||||||
|
|
||||||
def _active_trails(self) -> dict:
|
def _active_trails(self) -> dict:
|
||||||
if not self._trail_cb.isChecked():
|
if not self._trail_cb.isChecked():
|
||||||
@@ -192,7 +215,14 @@ class SkyTab(QWidget):
|
|||||||
selected = self._selected_rids()
|
selected = self._selected_rids()
|
||||||
return {key: list(dq)[-n_points:]
|
return {key: list(dq)[-n_points:]
|
||||||
for key, dq in self._trail.items()
|
for key, dq in self._trail.items()
|
||||||
if key[0] in selected}
|
if key[0] in selected and key[1] in self._enabled_gnss}
|
||||||
|
|
||||||
|
def _on_gnss_toggled(self, gid: int, checked: bool):
|
||||||
|
if checked:
|
||||||
|
self._enabled_gnss.add(gid)
|
||||||
|
else:
|
||||||
|
self._enabled_gnss.discard(gid)
|
||||||
|
self._refresh_immediate()
|
||||||
|
|
||||||
# ── Trail toggle ──────────────────────────────────────────────────────────
|
# ── Trail toggle ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
+1
-20
@@ -11,7 +11,7 @@ from PyQt5.QtWidgets import QWidget, QSizePolicy, QApplication
|
|||||||
from PyQt5.QtGui import (QPainter, QColor, QPen, QBrush, QFont, QImage)
|
from PyQt5.QtGui import (QPainter, QColor, QPen, QBrush, QFont, QImage)
|
||||||
from PyQt5.QtCore import Qt, QPointF, QRectF, QThread, pyqtSignal
|
from PyQt5.QtCore import Qt, QPointF, QRectF, QThread, pyqtSignal
|
||||||
|
|
||||||
from data_model import GNSS_NAMES, GNSS_COLORS, GNSS_SHORT
|
from data_model import GNSS_COLORS, GNSS_SHORT
|
||||||
|
|
||||||
# ── Static colors (created once in main thread, read-only in render thread) ──
|
# ── Static colors (created once in main thread, read-only in render thread) ──
|
||||||
_C_BG = QColor('#1a1a2e')
|
_C_BG = QColor('#1a1a2e')
|
||||||
@@ -92,7 +92,6 @@ class SkyRenderThread(QThread):
|
|||||||
if trails:
|
if trails:
|
||||||
self._draw_trails(p, cx, cy, max_r, trails)
|
self._draw_trails(p, cx, cy, max_r, trails)
|
||||||
self._draw_satellites(p, cx, cy, max_r, sats)
|
self._draw_satellites(p, cx, cy, max_r, sats)
|
||||||
self._draw_legend(p, sats)
|
|
||||||
|
|
||||||
p.end()
|
p.end()
|
||||||
return img
|
return img
|
||||||
@@ -184,24 +183,6 @@ class SkyRenderThread(QThread):
|
|||||||
p.drawText(QRectF(x + size + 1, y - 6, 28, 12),
|
p.drawText(QRectF(x + size + 1, y - 6, 28, 12),
|
||||||
Qt.AlignLeft, f"{short}{sat.sv_id}")
|
Qt.AlignLeft, f"{short}{sat.sv_id}")
|
||||||
|
|
||||||
def _draw_legend(self, p: QPainter, sats):
|
|
||||||
used = {sat.gnss_id for _, sat in sats}
|
|
||||||
if not used:
|
|
||||||
return
|
|
||||||
f = QFont(); f.setPointSize(8)
|
|
||||||
p.setFont(f)
|
|
||||||
lx, ly = 8, 8
|
|
||||||
for gid in sorted(used):
|
|
||||||
color = _GNSS_QCOLORS.get(gid)
|
|
||||||
if color is None:
|
|
||||||
continue
|
|
||||||
p.setBrush(QBrush(color))
|
|
||||||
p.setPen(Qt.NoPen)
|
|
||||||
p.drawEllipse(QPointF(lx + 5, ly + 6), 5, 5)
|
|
||||||
p.setPen(QPen(_C_SAT_LBL))
|
|
||||||
p.drawText(lx + 14, ly + 11, GNSS_NAMES.get(gid, f'SYS{gid}'))
|
|
||||||
ly += 18
|
|
||||||
|
|
||||||
|
|
||||||
# ── Widget ────────────────────────────────────────────────────────────────────
|
# ── Widget ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user