Files
radar_system/python_app/gui/controllers/sections/views.py
T
2026-10-06 12:32:26 +03:00

166 lines
4.9 KiB
Python

"""Typed section widgets and the scalar Qt boundary shared by GUI settings."""
from collections.abc import Callable
from dataclasses import dataclass, field
from typing import TypeAlias, TypeVar
from PyQt6.QtWidgets import (
QCheckBox, QComboBox, QDoubleSpinBox, QGroupBox, QLineEdit, QPlainTextEdit,
QSpinBox, QWidget, QLabel, QPushButton, QStackedWidget,
)
from python_app.gui.antenna_geometry_editor import AntennaGeometryEditor
from python_app.models.setting_fields import Scalar
ScalarWidget: TypeAlias = QLineEdit | QPlainTextEdit | QComboBox | QCheckBox | QSpinBox | QDoubleSpinBox
SettingWidget: TypeAlias = ScalarWidget | AntennaGeometryEditor
_Widget = TypeVar("_Widget", bound=SettingWidget)
@dataclass(slots=True)
class SectionView:
group: QGroupBox
fields: dict[str, SettingWidget] = field(default_factory=dict)
def add(self, name: str, widget: _Widget) -> _Widget:
self.fields[name] = widget
return widget
@dataclass(slots=True, kw_only=True)
class PreprocessView(SectionView):
labels: dict[str, QLabel]
@dataclass(slots=True, kw_only=True)
class PrimaryView(SectionView):
start: QPushButton
single_capture: QPushButton
stop: QPushButton
apply_radar: QPushButton
load: QPushButton
save: QPushButton
preprocess: QPushButton
clear: QPushButton
@dataclass(slots=True, kw_only=True)
class DataView(SectionView):
save: QPushButton
save_json: QPushButton
remove_last: QPushButton
capture_tmp: QPushButton
record: QPushButton
browse: QPushButton
save_path: QLineEdit
save_name: QLineEdit
record_count: QSpinBox
@dataclass(slots=True, kw_only=True)
class SwitchView(SectionView):
select_text: QPushButton
select_single: QPushButton
combos: QLineEdit
single_input: QLineEdit
single_output: QLineEdit
display_combo: QComboBox
next_combo: QPushButton
@dataclass(slots=True, kw_only=True)
class ProcessingView(SectionView):
mode: QComboBox
pages: QStackedWidget
geometry_page: QWidget
geometries: tuple[AntennaGeometryEditor, AntennaGeometryEditor]
fixed_y: QCheckBox
y_bounds: tuple[QDoubleSpinBox, QDoubleSpinBox]
speed_controls: tuple[tuple[QCheckBox, QDoubleSpinBox], ...]
trace_controls: tuple[ScalarWidget, ...]
visual_controls: tuple[ScalarWidget, ...]
locator_controls: tuple[ScalarWidget, ...]
frequency_controls: tuple[QDoubleSpinBox, ...]
@dataclass(slots=True, kw_only=True)
class RadarView(SectionView):
sweep_edits: tuple[QLineEdit, ...]
sweep_labels: tuple[QLabel, ...]
limits_hint: QLabel
vna_panel: QWidget
adc_panel: QWidget
optical_enabled: QCheckBox
optical_mode: QComboBox
optical_common: tuple[ScalarWidget, ...]
optical_manual: tuple[ScalarWidget, ...]
optical_variation: tuple[ScalarWidget, ...]
manual_panel: QWidget
variation_panel: QWidget
def read_setting(widget: ScalarWidget) -> Scalar:
if isinstance(widget, QCheckBox):
return widget.isChecked()
if isinstance(widget, (QSpinBox, QDoubleSpinBox)):
return widget.value()
if isinstance(widget, QComboBox):
return widget.currentText()
if isinstance(widget, QPlainTextEdit):
return widget.toPlainText()
return widget.text()
def write_setting(widget: ScalarWidget, value: Scalar) -> None:
if isinstance(widget, QCheckBox):
widget.setChecked(bool(value))
elif isinstance(widget, QSpinBox):
widget.setValue(int(value))
elif isinstance(widget, QDoubleSpinBox):
widget.setValue(float(value))
elif isinstance(widget, QComboBox):
text = str(value)
index = widget.findText(text)
if index < 0:
widget.addItem(text)
index = widget.count() - 1
widget.setCurrentIndex(index)
elif isinstance(widget, QPlainTextEdit):
widget.setPlainText(str(value))
else:
widget.setText(str(value))
def connect_setting(widget: ScalarWidget, callback: Callable[..., object]) -> None:
if isinstance(widget, QCheckBox):
signal = widget.toggled
elif isinstance(widget, (QSpinBox, QDoubleSpinBox)):
signal = widget.valueChanged
elif isinstance(widget, QComboBox):
signal = widget.currentTextChanged
elif isinstance(widget, QPlainTextEdit):
signal = widget.textChanged
else:
signal = widget.editingFinished
signal.connect(callback)
def double_spin(minimum: float, maximum: float, decimals: int, step: float) -> QDoubleSpinBox:
widget = QDoubleSpinBox()
widget.setDecimals(decimals)
widget.setRange(minimum, maximum)
widget.setSingleStep(step)
return widget
def integer_spin(minimum: int, maximum: int) -> QSpinBox:
widget = QSpinBox()
widget.setRange(minimum, maximum)
return widget
def choice(options: list[str]) -> QComboBox:
widget = QComboBox()
widget.addItems(options)
return widget