Polish GUI design
This commit is contained in:
@@ -10,11 +10,12 @@ import pyqtgraph as pg
|
||||
from PyQt6.QtCore import QSignalBlocker, QRectF, Qt, pyqtSignal
|
||||
from PyQt6.QtWidgets import (
|
||||
QCheckBox, QComboBox, QDialog, QDoubleSpinBox, QFormLayout, QGroupBox,
|
||||
QHBoxLayout, QHeaderView, QLabel, QLineEdit, QPushButton, QTableWidget, QTableWidgetItem,
|
||||
QHBoxLayout, QHeaderView, QLabel, QLineEdit, QPushButton, QScrollArea, QTableWidget, QTableWidgetItem,
|
||||
QToolButton, QVBoxLayout, QWidget,
|
||||
)
|
||||
|
||||
from python_app.models.dataset_model import SweepCollection
|
||||
from python_app.gui.theme import PLOT_BACKGROUND
|
||||
|
||||
|
||||
class ObjectCalibrationDialog(QDialog):
|
||||
@@ -33,7 +34,13 @@ class ObjectCalibrationDialog(QDialog):
|
||||
self._provenance: dict | None = None
|
||||
self._capture_pending = self._calculating = False
|
||||
self._calibration: dict | None = None
|
||||
layout = QVBoxLayout(self)
|
||||
root_layout = QVBoxLayout(self)
|
||||
scroll = QScrollArea(self)
|
||||
scroll.setWidgetResizable(True)
|
||||
content = QWidget(scroll)
|
||||
layout = QVBoxLayout(content)
|
||||
scroll.setWidget(content)
|
||||
root_layout.addWidget(scroll)
|
||||
name_row = QHBoxLayout()
|
||||
name_row.addWidget(QLabel("Set name", self))
|
||||
self._set_name_input = QLineEdit(set_name, self)
|
||||
@@ -49,6 +56,7 @@ class ObjectCalibrationDialog(QDialog):
|
||||
explanation.setWordWrap(True)
|
||||
layout.addWidget(explanation)
|
||||
self._table = QTableWidget(0, 5, self)
|
||||
self._table.setMaximumHeight(140)
|
||||
self._table.setHorizontalHeaderLabels(["Target", "Sweeps", "X (m)", "Y (m)", "Z (m)"])
|
||||
horizontal, vertical = self._table.horizontalHeader(), self._table.verticalHeader()
|
||||
assert horizontal is not None and vertical is not None
|
||||
@@ -57,9 +65,10 @@ class ObjectCalibrationDialog(QDialog):
|
||||
self._table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
||||
layout.addWidget(self._table)
|
||||
actions = QHBoxLayout()
|
||||
self._capture_button = QPushButton("Capture data", self)
|
||||
self._capture_button = QPushButton("Capture Data", self)
|
||||
self._capture_button.clicked.connect(self.capture_requested.emit)
|
||||
self._remove_button = QPushButton("Remove selected target", self)
|
||||
self._remove_button = QPushButton("Remove Selected Target", self)
|
||||
self._remove_button.setProperty("role", "destructive")
|
||||
self._remove_button.clicked.connect(self._remove_capture)
|
||||
actions.addWidget(self._capture_button)
|
||||
actions.addWidget(self._remove_button)
|
||||
@@ -68,27 +77,27 @@ class ObjectCalibrationDialog(QDialog):
|
||||
self._settings: dict[str, QDoubleSpinBox | QCheckBox | QComboBox] = {}
|
||||
form = QFormLayout()
|
||||
for key, title, default, low, high in (
|
||||
("sphere_radius_m", "Sphere radius, m (0 = point)", .16, 0, 100),
|
||||
("antenna_height_m", "Antenna origin height above ground, m", .92, 0, 100),
|
||||
("pitch_deg", "Radar downward tilt, °", 10, -90, 90),
|
||||
("sphere_radius_m", "Sphere radius (m, 0 = point)", .16, 0, 100),
|
||||
("antenna_height_m", "Antenna origin height above ground (m)", .92, 0, 100),
|
||||
("pitch_deg", "Radar downward tilt (°)", 10, -90, 90),
|
||||
):
|
||||
form.addRow(title, self._number(key, default, low, high))
|
||||
layout.addLayout(form)
|
||||
# A disclosure header: only the header shows until the operator opens it.
|
||||
advanced_toggle = QToolButton(self)
|
||||
advanced_toggle.setText("Calculation settings")
|
||||
advanced_toggle.setText("Calculation Settings")
|
||||
advanced_toggle.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||
advanced_toggle.setArrowType(Qt.ArrowType.RightArrow)
|
||||
advanced_toggle.setAutoRaise(True)
|
||||
advanced = QGroupBox(self)
|
||||
advanced_form = QFormLayout(advanced)
|
||||
for key, title, default, low, high in (
|
||||
("f_min", "Estimation band start, MHz", 2000, 0, 100000),
|
||||
("f_max", "Estimation band stop, MHz", 6000, 0, 100000),
|
||||
("gate_half_m", "Echo path gate half-width, m", .15, .000001, 100),
|
||||
("gate_taper_m", "Gate taper width, m", .03, .000001, 100),
|
||||
("coarse_range_search_m", "Coarse path search, ±m (0 = off)", .6, 0, 100),
|
||||
("refine_range_m", "Coordinate refinement, ±m", .1, 0, 100),
|
||||
("f_min", "Estimation band start (MHz)", 2000, 0, 100000),
|
||||
("f_max", "Estimation band stop (MHz)", 6000, 0, 100000),
|
||||
("gate_half_m", "Echo path gate half-width (m)", .15, .001, 100),
|
||||
("gate_taper_m", "Gate taper width (m)", .03, .001, 100),
|
||||
("coarse_range_search_m", "Coarse path search (±m, 0 = off)", .6, 0, 100),
|
||||
("refine_range_m", "Coordinate refinement (±m)", .1, 0, 100),
|
||||
):
|
||||
advanced_form.addRow(title, self._number(key, default, low, high))
|
||||
axes = QWidget(advanced)
|
||||
@@ -123,7 +132,7 @@ class ObjectCalibrationDialog(QDialog):
|
||||
self._target_combo = QComboBox(self)
|
||||
layout.addWidget(self._target_combo)
|
||||
self._phase_view = pg.GraphicsLayoutWidget(parent=self)
|
||||
self._phase_view.setBackground("#0f141c")
|
||||
self._phase_view.setBackground(PLOT_BACKGROUND)
|
||||
self._phase_view.setMinimumHeight(270)
|
||||
self._phase_plots = []
|
||||
self._phase_images = []
|
||||
@@ -154,9 +163,10 @@ class ObjectCalibrationDialog(QDialog):
|
||||
self._status_label.setWordWrap(True)
|
||||
layout.addWidget(self._status_label)
|
||||
footer = QHBoxLayout()
|
||||
self._calculate_button = QPushButton("Calculate and save", self)
|
||||
self._calculate_button = QPushButton("Calculate and Save", self)
|
||||
self._calculate_button.setProperty("role", "primary")
|
||||
self._calculate_button.clicked.connect(self.calculate_requested.emit)
|
||||
self._cancel_button = QPushButton("Cancel operation", self)
|
||||
self._cancel_button = QPushButton("Cancel Operation", self)
|
||||
self._cancel_button.clicked.connect(self.cancel_requested.emit)
|
||||
close_button = QPushButton("Close", self)
|
||||
close_button.clicked.connect(self.reject)
|
||||
@@ -164,7 +174,7 @@ class ObjectCalibrationDialog(QDialog):
|
||||
footer.addWidget(self._cancel_button)
|
||||
footer.addStretch(1)
|
||||
footer.addWidget(close_button)
|
||||
layout.addLayout(footer)
|
||||
root_layout.addLayout(footer)
|
||||
self._table.itemChanged.connect(self._measurements_changed)
|
||||
self._target_combo.currentIndexChanged.connect(self._draw_phase_effect)
|
||||
for field in [*self._settings.values(), *self._refine_axes.values()]:
|
||||
@@ -175,7 +185,7 @@ class ObjectCalibrationDialog(QDialog):
|
||||
|
||||
def _number(self, key: str, value: float, low: float, high: float) -> QDoubleSpinBox:
|
||||
field = QDoubleSpinBox(self)
|
||||
field.setDecimals(6)
|
||||
field.setDecimals(0 if key in {"f_min", "f_max"} else 1 if key == "pitch_deg" else 3)
|
||||
field.setRange(low, high)
|
||||
field.setSingleStep(100 if key in {"f_min", "f_max"} else .1 if key == "pitch_deg" else .01)
|
||||
field.setValue(value)
|
||||
|
||||
Reference in New Issue
Block a user