Rework radar system
This commit is contained in:
@@ -1,17 +1 @@
|
||||
"""Composable UI section builders used by AppWindow UI mixin."""
|
||||
|
||||
from python_app.gui.controllers.sections.data_actions_section import build_data_actions_group
|
||||
from python_app.gui.controllers.sections.primary_actions_section import build_primary_actions_group
|
||||
from python_app.gui.controllers.sections.preprocess_summary_section import build_preprocess_summary_group
|
||||
from python_app.gui.controllers.sections.processing_section import build_processing_group
|
||||
from python_app.gui.controllers.sections.radar_section import build_radar_group
|
||||
from python_app.gui.controllers.sections.switch_section import build_switch_group
|
||||
|
||||
__all__ = [
|
||||
"build_data_actions_group",
|
||||
"build_primary_actions_group",
|
||||
"build_preprocess_summary_group",
|
||||
"build_processing_group",
|
||||
"build_radar_group",
|
||||
"build_switch_group",
|
||||
]
|
||||
"""Typed configuration sections."""
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""Builder for snapshot and storage actions section."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt6.QtWidgets import (
|
||||
QGridLayout,
|
||||
QGroupBox,
|
||||
@@ -15,39 +13,39 @@ from PyQt6.QtWidgets import (
|
||||
)
|
||||
|
||||
|
||||
def build_data_actions_group(owner) -> QGroupBox:
|
||||
from python_app.gui.controllers.sections.views import DataView, SectionView
|
||||
from python_app.models.gui_profile_schema import GuiStateModel
|
||||
|
||||
|
||||
def build_data_actions_group(gui: GuiStateModel) -> DataView:
|
||||
"""Create snapshot save controls section."""
|
||||
group = QGroupBox("Data Actions")
|
||||
view = SectionView(QGroupBox("Data Actions"))
|
||||
group = view.group
|
||||
layout = QVBoxLayout(group)
|
||||
layout.setSpacing(8)
|
||||
data_defaults = owner._gui_defaults.data_actions
|
||||
data_defaults = gui.data_actions
|
||||
|
||||
save_button = QPushButton("Save Last 1000")
|
||||
save_button.setToolTip("Save up to 1000 most recent measurements with all available data stages.")
|
||||
save_button.clicked.connect(owner._save_snapshot)
|
||||
save_button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
save_vna_json_button = QPushButton("Save S21 JSON")
|
||||
save_vna_json_button.setToolTip(
|
||||
"Export one S21 VNA-history JSON per combo from the preprocessed stage (S11 is not included)."
|
||||
"Export one S21 VNA-history JSON per combo from the preprocessed stage."
|
||||
)
|
||||
save_vna_json_button.clicked.connect(owner._save_vna_history_json)
|
||||
save_vna_json_button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
remove_last_button = QPushButton("Remove Last Measurement")
|
||||
remove_last_button.clicked.connect(owner._remove_last_runtime_history)
|
||||
remove_last_button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
capture_tmp_reference_button = QPushButton("Capture Tmp Reference")
|
||||
capture_tmp_reference_button.clicked.connect(owner._capture_tmp_reference)
|
||||
capture_tmp_reference_button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
record_button = QPushButton("Start + Record to Disk")
|
||||
record_button.setToolTip(
|
||||
"Start the run (if stopped) and save the next N measurements to the path/name below."
|
||||
)
|
||||
record_button.clicked.connect(owner._start_run_with_recording)
|
||||
record_button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
owner._record_count = QSpinBox()
|
||||
owner._record_count.setMinimum(1)
|
||||
owner._record_count.setMaximum(1_000_000)
|
||||
owner._record_count.setValue(int(data_defaults.record_count))
|
||||
record_count = view.add("_record_count", QSpinBox())
|
||||
record_count.setMinimum(1)
|
||||
record_count.setMaximum(1_000_000)
|
||||
record_count.setValue(int(data_defaults.record_count))
|
||||
|
||||
button_grid = QGridLayout()
|
||||
button_grid.setHorizontalSpacing(8)
|
||||
@@ -64,24 +62,26 @@ def build_data_actions_group(owner) -> QGroupBox:
|
||||
record_count_row = QHBoxLayout()
|
||||
record_count_row.setSpacing(8)
|
||||
record_count_row.addWidget(QLabel("Number of Sweeps to Record"))
|
||||
record_count_row.addWidget(owner._record_count)
|
||||
record_count_row.addWidget(record_count)
|
||||
record_count_row.addStretch(1)
|
||||
layout.addLayout(record_count_row)
|
||||
|
||||
path_row = QHBoxLayout()
|
||||
path_row.setSpacing(8)
|
||||
owner._save_path_input = QLineEdit(str(data_defaults.save_path))
|
||||
save_path_input = view.add("_save_path_input", QLineEdit(str(data_defaults.save_path)))
|
||||
browse_button = QPushButton("Browse")
|
||||
browse_button.clicked.connect(owner._browse_save_path)
|
||||
path_row.addWidget(QLabel("Path"))
|
||||
path_row.addWidget(owner._save_path_input, stretch=1)
|
||||
path_row.addWidget(save_path_input, stretch=1)
|
||||
path_row.addWidget(browse_button)
|
||||
layout.addLayout(path_row)
|
||||
|
||||
name_row = QHBoxLayout()
|
||||
name_row.setSpacing(8)
|
||||
owner._save_name_input = QLineEdit(str(data_defaults.save_name))
|
||||
save_name_input = view.add("_save_name_input", QLineEdit(str(data_defaults.save_name)))
|
||||
name_row.addWidget(QLabel("Name"))
|
||||
name_row.addWidget(owner._save_name_input, stretch=1)
|
||||
name_row.addWidget(save_name_input, stretch=1)
|
||||
layout.addLayout(name_row)
|
||||
return group
|
||||
return DataView(group=group, fields=view.fields, save=save_button, save_json=save_vna_json_button,
|
||||
remove_last=remove_last_button, capture_tmp=capture_tmp_reference_button,
|
||||
record=record_button, browse=browse_button, save_path=save_path_input,
|
||||
save_name=save_name_input, record_count=record_count)
|
||||
|
||||
@@ -1,60 +1,33 @@
|
||||
"""Shared layout helpers for section builders."""
|
||||
|
||||
from __future__ import annotations
|
||||
"""Shared two-column form layout for settings sections."""
|
||||
|
||||
from typing import TypeAlias
|
||||
|
||||
from PyQt6.QtWidgets import QFormLayout, QHBoxLayout, QWidget
|
||||
|
||||
|
||||
FormLabel: TypeAlias = str | QWidget
|
||||
FormRow: TypeAlias = QWidget | tuple[FormLabel, QWidget]
|
||||
|
||||
|
||||
def build_two_column_form_widget(
|
||||
parent: QWidget,
|
||||
rows: list[FormRow],
|
||||
*,
|
||||
split_index: int | None = None,
|
||||
parent: QWidget, rows: list[FormRow], *, split_index: int | None = None,
|
||||
) -> QWidget:
|
||||
"""Build one widget containing two side-by-side form columns."""
|
||||
panel = QWidget(parent)
|
||||
panel_layout = QHBoxLayout(panel)
|
||||
panel_layout.setContentsMargins(0, 0, 0, 0)
|
||||
panel_layout.setSpacing(12)
|
||||
|
||||
left_column = QWidget(panel)
|
||||
left_form = _create_form_layout(left_column)
|
||||
right_column = QWidget(panel)
|
||||
right_form = _create_form_layout(right_column)
|
||||
|
||||
panel_layout.addWidget(left_column, stretch=1)
|
||||
panel_layout.addWidget(right_column, stretch=1)
|
||||
|
||||
actual_split_index = (len(rows) + 1) // 2 if split_index is None else split_index
|
||||
actual_split_index = max(0, min(actual_split_index, len(rows)))
|
||||
|
||||
for row in rows[:actual_split_index]:
|
||||
_add_form_row(left_form, row)
|
||||
for row in rows[actual_split_index:]:
|
||||
_add_form_row(right_form, row)
|
||||
layout = QHBoxLayout(panel)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(12)
|
||||
split = (len(rows) + 1) // 2 if split_index is None else max(0, min(split_index, len(rows)))
|
||||
for column_rows in (rows[:split], rows[split:]):
|
||||
column = QWidget(panel)
|
||||
form = QFormLayout(column)
|
||||
form.setContentsMargins(0, 0, 0, 0)
|
||||
form.setHorizontalSpacing(10)
|
||||
form.setVerticalSpacing(6)
|
||||
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||
for row in column_rows:
|
||||
if isinstance(row, tuple):
|
||||
label, widget = row
|
||||
form.addRow(label, widget)
|
||||
else:
|
||||
form.addRow(row)
|
||||
layout.addWidget(column, stretch=1)
|
||||
return panel
|
||||
|
||||
|
||||
def _create_form_layout(parent: QWidget) -> QFormLayout:
|
||||
"""Create a compact growing form layout for one column."""
|
||||
form = QFormLayout(parent)
|
||||
form.setContentsMargins(0, 0, 0, 0)
|
||||
form.setHorizontalSpacing(10)
|
||||
form.setVerticalSpacing(6)
|
||||
form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||
return form
|
||||
|
||||
|
||||
def _add_form_row(form: QFormLayout, row: FormRow) -> None:
|
||||
"""Append one form row, with or without an explicit label."""
|
||||
if isinstance(row, tuple):
|
||||
label, field = row
|
||||
form.addRow(label, field)
|
||||
return
|
||||
form.addRow(row)
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
"""Builder for preprocess set summary section."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt6.QtWidgets import QGroupBox, QLabel, QVBoxLayout
|
||||
|
||||
from python_app.gui.controllers.sections.layout_helpers import build_two_column_form_widget
|
||||
from python_app.orchestration.preprocess_assets import VISIBLE_PREPROCESS_ASSET_KEYS, preprocess_asset_display_name
|
||||
from python_app.gui.controllers.sections.layout_helpers import FormRow, build_two_column_form_widget
|
||||
from python_app.orchestration.preprocess_assets import PREPROCESS_ASSET_NAMES, preprocess_asset_display_name
|
||||
|
||||
from python_app.gui.controllers.sections.views import PreprocessView
|
||||
|
||||
|
||||
def build_preprocess_summary_group(owner) -> QGroupBox:
|
||||
def build_preprocess_summary_group() -> PreprocessView:
|
||||
"""Create selected preprocess-set summary section."""
|
||||
group = QGroupBox("Selected Preprocess Sets")
|
||||
view = PreprocessView(group=QGroupBox("Selected Preprocess Sets"), labels={})
|
||||
group = view.group
|
||||
layout = QVBoxLayout(group)
|
||||
layout.setContentsMargins(10, 10, 10, 10)
|
||||
layout.setSpacing(8)
|
||||
|
||||
owner._selected_preprocess_labels = {}
|
||||
rows = []
|
||||
for key in VISIBLE_PREPROCESS_ASSET_KEYS:
|
||||
rows: list[FormRow] = []
|
||||
for key in PREPROCESS_ASSET_NAMES:
|
||||
label = QLabel("<not selected>")
|
||||
owner._selected_preprocess_labels[key] = label
|
||||
view.labels[key] = label
|
||||
rows.append((preprocess_asset_display_name(key), label))
|
||||
|
||||
layout.addWidget(build_two_column_form_widget(group, rows, split_index=(len(rows) + 1) // 2))
|
||||
return group
|
||||
return view
|
||||
|
||||
@@ -1,57 +1,23 @@
|
||||
"""Builder for pinned primary action controls."""
|
||||
|
||||
from __future__ import annotations
|
||||
"""Pinned primary actions; controllers connect their own buttons."""
|
||||
|
||||
from PyQt6.QtWidgets import QGridLayout, QGroupBox, QPushButton, QSizePolicy
|
||||
|
||||
|
||||
def _expanding_button(label: str) -> QPushButton:
|
||||
"""Create horizontally expanding action button."""
|
||||
button = QPushButton(label)
|
||||
button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
return button
|
||||
from python_app.gui.controllers.sections.views import PrimaryView
|
||||
|
||||
|
||||
def build_primary_actions_group(owner) -> QGroupBox:
|
||||
"""Create pinned action block combining pipeline and hardware actions."""
|
||||
group = QGroupBox("Actions")
|
||||
layout = QGridLayout(group)
|
||||
def build_primary_actions_group() -> PrimaryView:
|
||||
view = PrimaryView(group=QGroupBox("Actions"), start=QPushButton("Start"),
|
||||
single_capture=QPushButton("Single Capture"), stop=QPushButton("Stop"),
|
||||
apply_radar=QPushButton("Apply Radar"), load=QPushButton("Load Config"),
|
||||
save=QPushButton("Save Config"), preprocess=QPushButton("Preprocessing"),
|
||||
clear=QPushButton("Clear Runtime History"))
|
||||
layout = QGridLayout(view.group)
|
||||
layout.setHorizontalSpacing(8)
|
||||
layout.setVerticalSpacing(8)
|
||||
|
||||
start_button = _expanding_button("Start")
|
||||
start_button.clicked.connect(owner._start_run)
|
||||
layout.addWidget(start_button, 0, 0)
|
||||
|
||||
single_button = _expanding_button("Single Capture")
|
||||
single_button.clicked.connect(owner._start_single_capture)
|
||||
layout.addWidget(single_button, 0, 1)
|
||||
|
||||
stop_button = _expanding_button("Stop")
|
||||
stop_button.clicked.connect(owner._stop_run)
|
||||
layout.addWidget(stop_button, 0, 2)
|
||||
|
||||
apply_radar_button = _expanding_button("Apply Radar")
|
||||
apply_radar_button.clicked.connect(owner._apply_radar_settings)
|
||||
layout.addWidget(apply_radar_button, 1, 0)
|
||||
|
||||
load_config_button = _expanding_button("Load Config")
|
||||
load_config_button.clicked.connect(owner._load_config_from_dialog)
|
||||
layout.addWidget(load_config_button, 1, 1)
|
||||
|
||||
save_config_button = _expanding_button("Save Config")
|
||||
save_config_button.clicked.connect(owner._save_current_config)
|
||||
layout.addWidget(save_config_button, 1, 2)
|
||||
|
||||
preprocess_button = _expanding_button("Preprocessing")
|
||||
preprocess_button.clicked.connect(owner._open_preprocess_panel)
|
||||
layout.addWidget(preprocess_button, 2, 0)
|
||||
|
||||
clear_history_button = _expanding_button("Clear Runtime History")
|
||||
clear_history_button.clicked.connect(owner._clear_all_runtime_history)
|
||||
layout.addWidget(clear_history_button, 2, 1, 1, 2)
|
||||
|
||||
layout.setColumnStretch(0, 1)
|
||||
layout.setColumnStretch(1, 1)
|
||||
layout.setColumnStretch(2, 1)
|
||||
return group
|
||||
for index, button in enumerate((view.start, view.single_capture, view.stop, view.apply_radar,
|
||||
view.load, view.save, view.preprocess, view.clear)):
|
||||
button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
layout.addWidget(button, index // 3, index % 3, 1, 2 if button is view.clear else 1)
|
||||
for column in range(3):
|
||||
layout.setColumnStretch(column, 1)
|
||||
return view
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,5 @@
|
||||
"""Builder for radar settings section."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from PyQt6.QtWidgets import (
|
||||
@@ -16,103 +14,109 @@ from PyQt6.QtWidgets import (
|
||||
)
|
||||
|
||||
from python_app.gui.controllers.sections.layout_helpers import build_two_column_form_widget
|
||||
from python_app.gui.controllers.sections.views import RadarView, SectionView, write_setting
|
||||
from python_app.models.run_config_schema import RunConfigModel
|
||||
|
||||
|
||||
def build_radar_group(owner) -> QGroupBox:
|
||||
def build_radar_group(config: RunConfigModel) -> RadarView:
|
||||
"""Create radar settings controls and labels."""
|
||||
group = QGroupBox("Radar")
|
||||
view = SectionView(QGroupBox("Radar"))
|
||||
group = view.group
|
||||
layout = QVBoxLayout(group)
|
||||
layout.setContentsMargins(10, 10, 10, 10)
|
||||
layout.setSpacing(8)
|
||||
defaults = owner._defaults_config.radar
|
||||
defaults = config.radar
|
||||
|
||||
owner._vna_radar_settings_panel = QWidget(group)
|
||||
vna_layout = QVBoxLayout(owner._vna_radar_settings_panel)
|
||||
vna_radar_settings_panel = QWidget(group)
|
||||
vna_layout = QVBoxLayout(vna_radar_settings_panel)
|
||||
vna_layout.setContentsMargins(0, 0, 0, 0)
|
||||
vna_layout.setSpacing(8)
|
||||
|
||||
owner._start_hz_input = QLineEdit(f"{defaults.sweep.start_hz:g}")
|
||||
owner._stop_hz_input = QLineEdit(f"{defaults.sweep.stop_hz:g}")
|
||||
owner._points_input = QLineEdit(str(defaults.sweep.points))
|
||||
owner._ifbw_input = QLineEdit(f"{defaults.sweep.if_bandwidth_hz:g}")
|
||||
owner._power_input = QLineEdit(f"{defaults.sweep.power_dbm:g}")
|
||||
owner._power_input.setToolTip("Stimulus power configured in the active profile.")
|
||||
owner._start_hz_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
|
||||
owner._stop_hz_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
|
||||
owner._points_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
|
||||
owner._ifbw_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
|
||||
owner._power_input.editingFinished.connect(owner._on_radar_sweep_limits_changed)
|
||||
start_hz_input = view.add("_start_hz_input", QLineEdit(f"{defaults.sweep.start_hz:g}"))
|
||||
stop_hz_input = view.add("_stop_hz_input", QLineEdit(f"{defaults.sweep.stop_hz:g}"))
|
||||
points_input = view.add("_points_input", QLineEdit(str(defaults.sweep.points)))
|
||||
ifbw_input = view.add("_ifbw_input", QLineEdit(f"{defaults.sweep.if_bandwidth_hz:g}"))
|
||||
power_input = view.add("_power_input", QLineEdit(f"{defaults.sweep.power_dbm:g}"))
|
||||
power_input.setToolTip("Stimulus power configured in the active profile.")
|
||||
|
||||
owner._radar_start_label = QLabel("Start Hz")
|
||||
owner._radar_stop_label = QLabel("Stop Hz")
|
||||
owner._radar_points_label = QLabel("Points")
|
||||
owner._radar_ifbw_label = QLabel("IF BW Hz")
|
||||
owner._radar_power_label = QLabel("Stimulus Power dBm")
|
||||
radar_start_label = QLabel("Start Hz")
|
||||
radar_stop_label = QLabel("Stop Hz")
|
||||
radar_points_label = QLabel("Points")
|
||||
radar_ifbw_label = QLabel("IF BW Hz")
|
||||
radar_power_label = QLabel("Stimulus Power dBm")
|
||||
|
||||
owner._radar_limits_hint = QLabel("Device limits are not available.")
|
||||
owner._radar_limits_hint.setObjectName("hintLabel")
|
||||
radar_limits_hint = QLabel("Device limits are not available.")
|
||||
radar_limits_hint.setObjectName("hintLabel")
|
||||
|
||||
vna_layout.addWidget(
|
||||
build_two_column_form_widget(
|
||||
group,
|
||||
[
|
||||
(owner._radar_start_label, owner._start_hz_input),
|
||||
(owner._radar_stop_label, owner._stop_hz_input),
|
||||
(owner._radar_points_label, owner._points_input),
|
||||
(owner._radar_ifbw_label, owner._ifbw_input),
|
||||
(owner._radar_power_label, owner._power_input),
|
||||
(radar_start_label, start_hz_input),
|
||||
(radar_stop_label, stop_hz_input),
|
||||
(radar_points_label, points_input),
|
||||
(radar_ifbw_label, ifbw_input),
|
||||
(radar_power_label, power_input),
|
||||
],
|
||||
)
|
||||
)
|
||||
vna_layout.addWidget(owner._radar_limits_hint)
|
||||
vna_layout.addWidget(radar_limits_hint)
|
||||
|
||||
owner._adc_radar_settings_panel = _build_adc_settings_panel(owner, group)
|
||||
(adc_radar_settings_panel, optical_enabled, optical_mode, optical_common, optical_manual,
|
||||
optical_variation, manual_panel, variation_panel) = _build_adc_settings_panel(view, config)
|
||||
|
||||
layout.addWidget(owner._vna_radar_settings_panel)
|
||||
layout.addWidget(owner._adc_radar_settings_panel)
|
||||
owner._set_radar_settings_mode(owner._defaults_config.is_kamil_adc)
|
||||
return group
|
||||
layout.addWidget(vna_radar_settings_panel)
|
||||
layout.addWidget(adc_radar_settings_panel)
|
||||
vna_radar_settings_panel.setVisible(not config.is_kamil_adc)
|
||||
adc_radar_settings_panel.setVisible(config.is_kamil_adc)
|
||||
return RadarView(group=group, fields=view.fields,
|
||||
sweep_edits=(start_hz_input, stop_hz_input, points_input, ifbw_input, power_input),
|
||||
sweep_labels=(radar_start_label, radar_stop_label, radar_points_label, radar_ifbw_label, radar_power_label),
|
||||
limits_hint=radar_limits_hint, vna_panel=vna_radar_settings_panel, adc_panel=adc_radar_settings_panel,
|
||||
optical_enabled=optical_enabled, optical_mode=optical_mode, optical_common=optical_common,
|
||||
optical_manual=optical_manual, optical_variation=optical_variation,
|
||||
manual_panel=manual_panel, variation_panel=variation_panel)
|
||||
|
||||
|
||||
def _build_adc_settings_panel(owner, parent: QWidget) -> QWidget:
|
||||
def _build_adc_settings_panel(view: SectionView, config: RunConfigModel):
|
||||
"""Create controls for the external ADC collector and optical board."""
|
||||
panel = QWidget(parent)
|
||||
panel = QWidget(view.group)
|
||||
layout = QVBoxLayout(panel)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(8)
|
||||
|
||||
adc = owner._defaults_config.radar.kamil_adc
|
||||
optical = owner._defaults_config.radar.laser_control
|
||||
adc = config.radar.kamil_adc
|
||||
optical = config.radar.laser_control
|
||||
manual = optical.manual
|
||||
variation = optical.variation
|
||||
|
||||
owner._adc_project_dir_input = QLineEdit(adc.project_dir)
|
||||
owner._adc_executable_path_input = QLineEdit(adc.executable_path)
|
||||
owner._adc_tty_path_input = QLineEdit(adc.tty_path)
|
||||
owner._adc_args_input = _plain_text("\n".join(adc.args))
|
||||
owner._adc_env_input = _plain_text(json.dumps(adc.env, indent=2, sort_keys=True) if adc.env else "{}")
|
||||
owner._adc_startup_timeout_s_input = QLineEdit(f"{adc.startup_timeout_s:g}")
|
||||
owner._adc_sweep_timeout_s_input = QLineEdit(f"{adc.sweep_timeout_s:g}")
|
||||
owner._adc_stop_timeout_s_input = QLineEdit(f"{adc.stop_timeout_s:g}")
|
||||
adc_project_dir_input = view.add("_adc_project_dir_input", QLineEdit(adc.project_dir))
|
||||
adc_executable_path_input = view.add("_adc_executable_path_input", QLineEdit(adc.executable_path))
|
||||
adc_tty_path_input = view.add("_adc_tty_path_input", QLineEdit(adc.tty_path))
|
||||
adc_args_input = view.add("_adc_args_input", _plain_text("\n".join(adc.args)))
|
||||
adc_env_input = view.add("_adc_env_input", _plain_text(json.dumps(adc.env, indent=2, sort_keys=True) if adc.env else "{}"))
|
||||
adc_startup_timeout_s_input = view.add("_adc_startup_timeout_s_input", QLineEdit(f"{adc.startup_timeout_s:g}"))
|
||||
adc_sweep_timeout_s_input = view.add("_adc_sweep_timeout_s_input", QLineEdit(f"{adc.sweep_timeout_s:g}"))
|
||||
adc_stop_timeout_s_input = view.add("_adc_stop_timeout_s_input", QLineEdit(f"{adc.stop_timeout_s:g}"))
|
||||
|
||||
owner._optical_enabled_checkbox = QCheckBox()
|
||||
owner._optical_enabled_checkbox.setChecked(bool(optical.enabled))
|
||||
owner._optical_port_input = QLineEdit(optical.port)
|
||||
owner._optical_mode_combo = QComboBox()
|
||||
owner._optical_mode_combo.addItems(["manual", "variation"])
|
||||
owner._set_combo_current_text(owner._optical_mode_combo, optical.mode)
|
||||
owner._optical_pi_coeff1_p_input = QLineEdit(str(optical.pi_coeff1_p))
|
||||
owner._optical_pi_coeff1_i_input = QLineEdit(str(optical.pi_coeff1_i))
|
||||
owner._optical_pi_coeff2_p_input = QLineEdit(str(optical.pi_coeff2_p))
|
||||
owner._optical_pi_coeff2_i_input = QLineEdit(str(optical.pi_coeff2_i))
|
||||
optical_enabled_checkbox = view.add("_optical_enabled_checkbox", QCheckBox())
|
||||
optical_enabled_checkbox.setChecked(bool(optical.enabled))
|
||||
optical_port_input = view.add("_optical_port_input", QLineEdit(optical.port))
|
||||
optical_mode_combo = view.add("_optical_mode_combo", QComboBox())
|
||||
optical_mode_combo.addItems(["manual", "variation"])
|
||||
write_setting(optical_mode_combo, optical.mode)
|
||||
optical_pi_coeff1_p_input = view.add("_optical_pi_coeff1_p_input", QLineEdit(str(optical.pi_coeff1_p)))
|
||||
optical_pi_coeff1_i_input = view.add("_optical_pi_coeff1_i_input", QLineEdit(str(optical.pi_coeff1_i)))
|
||||
optical_pi_coeff2_p_input = view.add("_optical_pi_coeff2_p_input", QLineEdit(str(optical.pi_coeff2_p)))
|
||||
optical_pi_coeff2_i_input = view.add("_optical_pi_coeff2_i_input", QLineEdit(str(optical.pi_coeff2_i)))
|
||||
|
||||
owner._optical_manual_temp1_input = QLineEdit(f"{manual.temp1:g}")
|
||||
owner._optical_manual_temp2_input = QLineEdit(f"{manual.temp2:g}")
|
||||
owner._optical_manual_current1_input = QLineEdit(f"{manual.current1:g}")
|
||||
owner._optical_manual_current2_input = QLineEdit(f"{manual.current2:g}")
|
||||
optical_manual_temp1_input = view.add("_optical_manual_temp1_input", QLineEdit(f"{manual.temp1:g}"))
|
||||
optical_manual_temp2_input = view.add("_optical_manual_temp2_input", QLineEdit(f"{manual.temp2:g}"))
|
||||
optical_manual_current1_input = view.add("_optical_manual_current1_input", QLineEdit(f"{manual.current1:g}"))
|
||||
optical_manual_current2_input = view.add("_optical_manual_current2_input", QLineEdit(f"{manual.current2:g}"))
|
||||
|
||||
owner._optical_variation_type_combo = QComboBox()
|
||||
owner._optical_variation_type_combo.addItems(
|
||||
optical_variation_type_combo = view.add("_optical_variation_type_combo", QComboBox())
|
||||
optical_variation_type_combo.addItems(
|
||||
[
|
||||
"CHANGE_CURRENT_LD1",
|
||||
"CHANGE_CURRENT_LD2",
|
||||
@@ -120,118 +124,80 @@ def _build_adc_settings_panel(owner, parent: QWidget) -> QWidget:
|
||||
"CHANGE_TEMPERATURE_LD2",
|
||||
]
|
||||
)
|
||||
owner._set_combo_current_text(owner._optical_variation_type_combo, variation.variation_type)
|
||||
owner._optical_static_temp1_input = QLineEdit(f"{variation.static_temp1:g}")
|
||||
owner._optical_static_temp2_input = QLineEdit(f"{variation.static_temp2:g}")
|
||||
owner._optical_static_current1_input = QLineEdit(f"{variation.static_current1:g}")
|
||||
owner._optical_static_current2_input = QLineEdit(f"{variation.static_current2:g}")
|
||||
owner._optical_min_value_input = QLineEdit(f"{variation.min_value:g}")
|
||||
owner._optical_max_value_input = QLineEdit(f"{variation.max_value:g}")
|
||||
owner._optical_step_input = QLineEdit(f"{variation.step:g}")
|
||||
owner._optical_time_step_input = QLineEdit(str(variation.time_step))
|
||||
owner._optical_delay_time_input = QLineEdit(str(variation.delay_time))
|
||||
write_setting(optical_variation_type_combo, variation.variation_type)
|
||||
optical_static_temp1_input = view.add("_optical_static_temp1_input", QLineEdit(f"{variation.static_temp1:g}"))
|
||||
optical_static_temp2_input = view.add("_optical_static_temp2_input", QLineEdit(f"{variation.static_temp2:g}"))
|
||||
optical_static_current1_input = view.add("_optical_static_current1_input", QLineEdit(f"{variation.static_current1:g}"))
|
||||
optical_static_current2_input = view.add("_optical_static_current2_input", QLineEdit(f"{variation.static_current2:g}"))
|
||||
optical_min_value_input = view.add("_optical_min_value_input", QLineEdit(f"{variation.min_value:g}"))
|
||||
optical_max_value_input = view.add("_optical_max_value_input", QLineEdit(f"{variation.max_value:g}"))
|
||||
optical_step_input = view.add("_optical_step_input", QLineEdit(f"{variation.step:g}"))
|
||||
optical_time_step_input = view.add("_optical_time_step_input", QLineEdit(str(variation.time_step)))
|
||||
optical_delay_time_input = view.add("_optical_delay_time_input", QLineEdit(str(variation.delay_time)))
|
||||
|
||||
layout.addWidget(
|
||||
build_two_column_form_widget(
|
||||
panel,
|
||||
[
|
||||
("Project dir", owner._adc_project_dir_input),
|
||||
("Executable path", owner._adc_executable_path_input),
|
||||
("TTY path", owner._adc_tty_path_input),
|
||||
("Arguments", owner._adc_args_input),
|
||||
("Environment JSON", owner._adc_env_input),
|
||||
("Startup timeout s", owner._adc_startup_timeout_s_input),
|
||||
("Read timeout s", owner._adc_sweep_timeout_s_input),
|
||||
("Stop timeout s", owner._adc_stop_timeout_s_input),
|
||||
("Board enabled", owner._optical_enabled_checkbox),
|
||||
("Board port", owner._optical_port_input),
|
||||
("Board mode", owner._optical_mode_combo),
|
||||
("PI 1 P", owner._optical_pi_coeff1_p_input),
|
||||
("PI 1 I", owner._optical_pi_coeff1_i_input),
|
||||
("PI 2 P", owner._optical_pi_coeff2_p_input),
|
||||
("PI 2 I", owner._optical_pi_coeff2_i_input),
|
||||
("Project dir", adc_project_dir_input),
|
||||
("Executable path", adc_executable_path_input),
|
||||
("TTY path", adc_tty_path_input),
|
||||
("Arguments", adc_args_input),
|
||||
("Environment JSON", adc_env_input),
|
||||
("Startup timeout s", adc_startup_timeout_s_input),
|
||||
("Read timeout s", adc_sweep_timeout_s_input),
|
||||
("Stop timeout s", adc_stop_timeout_s_input),
|
||||
("Board enabled", optical_enabled_checkbox),
|
||||
("Board port", optical_port_input),
|
||||
("Board mode", optical_mode_combo),
|
||||
("PI 1 P", optical_pi_coeff1_p_input),
|
||||
("PI 1 I", optical_pi_coeff1_i_input),
|
||||
("PI 2 P", optical_pi_coeff2_p_input),
|
||||
("PI 2 I", optical_pi_coeff2_i_input),
|
||||
],
|
||||
split_index=8,
|
||||
)
|
||||
)
|
||||
|
||||
owner._optical_manual_panel = build_two_column_form_widget(
|
||||
optical_manual_panel = build_two_column_form_widget(
|
||||
panel,
|
||||
[
|
||||
("Temperature 1", owner._optical_manual_temp1_input),
|
||||
("Temperature 2", owner._optical_manual_temp2_input),
|
||||
("Current 1", owner._optical_manual_current1_input),
|
||||
("Current 2", owner._optical_manual_current2_input),
|
||||
("Temperature 1", optical_manual_temp1_input),
|
||||
("Temperature 2", optical_manual_temp2_input),
|
||||
("Current 1", optical_manual_current1_input),
|
||||
("Current 2", optical_manual_current2_input),
|
||||
],
|
||||
)
|
||||
owner._optical_variation_panel = build_two_column_form_widget(
|
||||
optical_variation_panel = build_two_column_form_widget(
|
||||
panel,
|
||||
[
|
||||
("Variation type", owner._optical_variation_type_combo),
|
||||
("Static temp 1", owner._optical_static_temp1_input),
|
||||
("Static temp 2", owner._optical_static_temp2_input),
|
||||
("Static current 1", owner._optical_static_current1_input),
|
||||
("Static current 2", owner._optical_static_current2_input),
|
||||
("Min value", owner._optical_min_value_input),
|
||||
("Max value", owner._optical_max_value_input),
|
||||
("Step", owner._optical_step_input),
|
||||
("Time step", owner._optical_time_step_input),
|
||||
("Delay time", owner._optical_delay_time_input),
|
||||
("Variation type", optical_variation_type_combo),
|
||||
("Static temp 1", optical_static_temp1_input),
|
||||
("Static temp 2", optical_static_temp2_input),
|
||||
("Static current 1", optical_static_current1_input),
|
||||
("Static current 2", optical_static_current2_input),
|
||||
("Min value", optical_min_value_input),
|
||||
("Max value", optical_max_value_input),
|
||||
("Step", optical_step_input),
|
||||
("Time step", optical_time_step_input),
|
||||
("Delay time", optical_delay_time_input),
|
||||
],
|
||||
split_index=5,
|
||||
)
|
||||
layout.addWidget(owner._optical_manual_panel)
|
||||
layout.addWidget(owner._optical_variation_panel)
|
||||
layout.addWidget(optical_manual_panel)
|
||||
layout.addWidget(optical_variation_panel)
|
||||
|
||||
_connect_adc_settings(owner)
|
||||
owner._sync_adc_settings_controls()
|
||||
return panel
|
||||
return (panel, optical_enabled_checkbox, optical_mode_combo,
|
||||
(optical_port_input, optical_mode_combo, optical_pi_coeff1_p_input, optical_pi_coeff1_i_input,
|
||||
optical_pi_coeff2_p_input, optical_pi_coeff2_i_input),
|
||||
(optical_manual_temp1_input, optical_manual_temp2_input, optical_manual_current1_input, optical_manual_current2_input),
|
||||
(optical_variation_type_combo, optical_static_temp1_input, optical_static_temp2_input,
|
||||
optical_static_current1_input, optical_static_current2_input, optical_min_value_input,
|
||||
optical_max_value_input, optical_step_input, optical_time_step_input, optical_delay_time_input),
|
||||
optical_manual_panel, optical_variation_panel)
|
||||
|
||||
|
||||
def _plain_text(text: str) -> QPlainTextEdit:
|
||||
widget = QPlainTextEdit(text)
|
||||
widget.setMaximumHeight(76)
|
||||
return widget
|
||||
|
||||
|
||||
def _connect_adc_settings(owner) -> None:
|
||||
text_widgets = [
|
||||
owner._adc_project_dir_input,
|
||||
owner._adc_executable_path_input,
|
||||
owner._adc_tty_path_input,
|
||||
owner._adc_startup_timeout_s_input,
|
||||
owner._adc_sweep_timeout_s_input,
|
||||
owner._adc_stop_timeout_s_input,
|
||||
owner._optical_port_input,
|
||||
owner._optical_pi_coeff1_p_input,
|
||||
owner._optical_pi_coeff1_i_input,
|
||||
owner._optical_pi_coeff2_p_input,
|
||||
owner._optical_pi_coeff2_i_input,
|
||||
owner._optical_manual_temp1_input,
|
||||
owner._optical_manual_temp2_input,
|
||||
owner._optical_manual_current1_input,
|
||||
owner._optical_manual_current2_input,
|
||||
owner._optical_static_temp1_input,
|
||||
owner._optical_static_temp2_input,
|
||||
owner._optical_static_current1_input,
|
||||
owner._optical_static_current2_input,
|
||||
owner._optical_min_value_input,
|
||||
owner._optical_max_value_input,
|
||||
owner._optical_step_input,
|
||||
owner._optical_time_step_input,
|
||||
owner._optical_delay_time_input,
|
||||
]
|
||||
for widget in text_widgets:
|
||||
widget.editingFinished.connect(owner._reset_preprocess_selection_after_radar_key_change)
|
||||
owner._adc_args_input.textChanged.connect(owner._reset_preprocess_selection_after_radar_key_change)
|
||||
owner._adc_env_input.textChanged.connect(owner._reset_preprocess_selection_after_radar_key_change)
|
||||
owner._optical_variation_type_combo.currentTextChanged.connect(
|
||||
owner._reset_preprocess_selection_after_radar_key_change
|
||||
)
|
||||
|
||||
def sync_and_reset() -> None:
|
||||
owner._sync_adc_settings_controls()
|
||||
owner._reset_preprocess_selection_after_radar_key_change()
|
||||
|
||||
owner._optical_enabled_checkbox.toggled.connect(sync_and_reset)
|
||||
owner._optical_mode_combo.currentTextChanged.connect(sync_and_reset)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"""Builder for switch timing and combo-selection settings section."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt6.QtWidgets import (
|
||||
QButtonGroup,
|
||||
QComboBox,
|
||||
QFormLayout,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
@@ -13,64 +12,71 @@ from PyQt6.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
def build_switch_group(owner) -> QGroupBox:
|
||||
from python_app.gui.controllers.sections.views import SwitchView, SectionView
|
||||
from python_app.models.gui_profile_schema import GuiStateModel
|
||||
from python_app.models.run_config_schema import RunConfigModel
|
||||
|
||||
|
||||
def build_switch_group(config: RunConfigModel, gui: GuiStateModel) -> SwitchView:
|
||||
"""Create switch timing field and two explicit combo-selection modes."""
|
||||
group = QGroupBox("Switches")
|
||||
view = SectionView(QGroupBox("Switches"))
|
||||
group = view.group
|
||||
layout = QVBoxLayout(group)
|
||||
layout.setSpacing(8)
|
||||
|
||||
switch_defaults = owner._gui_defaults.switches
|
||||
switch_defaults = gui.switches
|
||||
|
||||
global_form = QFormLayout()
|
||||
global_form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
|
||||
owner._settling_ms = QLineEdit(str(owner._defaults_config.runtime.settling_ms))
|
||||
global_form.addRow("Settling ms", owner._settling_ms)
|
||||
settling_ms = view.add("_settling_ms", QLineEdit(str(config.runtime.settling_ms)))
|
||||
global_form.addRow("Settling ms", settling_ms)
|
||||
layout.addLayout(global_form)
|
||||
|
||||
owner._combos_text = QLineEdit(str(switch_defaults.combos_text))
|
||||
owner._combos_text.setPlaceholderText("empty = full matrix, or input:output,input:output")
|
||||
owner._run_combos_select_button = QPushButton("Select")
|
||||
owner._run_combos_select_button.setCheckable(True)
|
||||
combos_text = view.add("_combos_text", QLineEdit(str(switch_defaults.combos_text)))
|
||||
combos_text.setPlaceholderText("empty = full matrix, or input:output,input:output")
|
||||
run_combos_select_button = QPushButton("Select")
|
||||
run_combos_select_button.setCheckable(True)
|
||||
|
||||
combos_row = QHBoxLayout()
|
||||
combos_row.setSpacing(8)
|
||||
combos_row.addWidget(QLabel("Run combos"))
|
||||
combos_row.addWidget(owner._combos_text, stretch=1)
|
||||
combos_row.addWidget(owner._run_combos_select_button)
|
||||
combos_row.addWidget(combos_text, stretch=1)
|
||||
combos_row.addWidget(run_combos_select_button)
|
||||
layout.addLayout(combos_row)
|
||||
|
||||
owner._single_combo_output = QLineEdit(str(switch_defaults.single_output))
|
||||
owner._single_combo_output.setPlaceholderText("0")
|
||||
owner._single_combo_input = QLineEdit(str(switch_defaults.single_input))
|
||||
owner._single_combo_input.setPlaceholderText("0")
|
||||
owner._single_combo_select_button = QPushButton("Select")
|
||||
owner._single_combo_select_button.setCheckable(True)
|
||||
owner._next_combo_button = QPushButton("Next combination")
|
||||
owner._next_combo_button.setToolTip("Advance through input/output pairs and redraw the selected B-scan.")
|
||||
single_combo_output = view.add("_single_combo_output", QLineEdit(str(switch_defaults.single_output)))
|
||||
single_combo_output.setPlaceholderText("0")
|
||||
single_combo_input = view.add("_single_combo_input", QLineEdit(str(switch_defaults.single_input)))
|
||||
single_combo_input.setPlaceholderText("0")
|
||||
single_combo_select_button = QPushButton("Select")
|
||||
single_combo_select_button.setCheckable(True)
|
||||
|
||||
single_row = QHBoxLayout()
|
||||
single_row.setSpacing(8)
|
||||
single_row.addWidget(QLabel("Single combo"))
|
||||
single_row.addWidget(QLabel("Input"))
|
||||
single_row.addWidget(owner._single_combo_input)
|
||||
single_row.addWidget(single_combo_input)
|
||||
single_row.addWidget(QLabel("Output"))
|
||||
single_row.addWidget(owner._single_combo_output)
|
||||
single_row.addWidget(owner._single_combo_select_button)
|
||||
single_row.addWidget(owner._next_combo_button)
|
||||
single_row.addWidget(single_combo_output)
|
||||
single_row.addWidget(single_combo_select_button)
|
||||
layout.addLayout(single_row)
|
||||
|
||||
owner._combo_select_group = QButtonGroup(group)
|
||||
owner._combo_select_group.setExclusive(True)
|
||||
owner._combo_select_group.addButton(owner._run_combos_select_button)
|
||||
owner._combo_select_group.addButton(owner._single_combo_select_button)
|
||||
combo_select_group = QButtonGroup(group)
|
||||
combo_select_group.setExclusive(True)
|
||||
combo_select_group.addButton(run_combos_select_button)
|
||||
combo_select_group.addButton(single_combo_select_button)
|
||||
|
||||
owner._run_combos_select_button.clicked.connect(lambda: owner._set_combo_selection_mode("text"))
|
||||
owner._single_combo_select_button.clicked.connect(lambda: owner._set_combo_selection_mode("single"))
|
||||
owner._next_combo_button.clicked.connect(owner._select_next_combo)
|
||||
# The live processing config has no combo: picking another one only changes which
|
||||
# B-scan is shown (and, outside matrix mode, the combo of the next run).
|
||||
owner._single_combo_output.editingFinished.connect(owner._on_bscan_display_combo_changed)
|
||||
owner._single_combo_input.editingFinished.connect(owner._on_bscan_display_combo_changed)
|
||||
owner._set_combo_selection_mode(str(switch_defaults.combo_mode))
|
||||
display_row = QHBoxLayout()
|
||||
display_row.addWidget(QLabel("B-scan pair"))
|
||||
display_combo = view.add("_display_combo", QComboBox())
|
||||
display_combo.setEnabled(False)
|
||||
display_row.addWidget(display_combo, stretch=1)
|
||||
next_combo_button = QPushButton("Next combination")
|
||||
next_combo_button.setEnabled(False)
|
||||
display_row.addWidget(next_combo_button)
|
||||
layout.addLayout(display_row)
|
||||
|
||||
return group
|
||||
return SwitchView(group=group, fields=view.fields, select_text=run_combos_select_button,
|
||||
select_single=single_combo_select_button, combos=combos_text,
|
||||
single_input=single_combo_input, single_output=single_combo_output,
|
||||
display_combo=display_combo, next_combo=next_combo_button)
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user