166 lines
4.9 KiB
Python
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
|