diff --git a/src/frog/gui/measure_script/script_run_dialog.py b/src/frog/gui/measure_script/script_run_dialog.py index cd4dd64d..763da683 100644 --- a/src/frog/gui/measure_script/script_run_dialog.py +++ b/src/frog/gui/measure_script/script_run_dialog.py @@ -89,7 +89,7 @@ def _update(self, script_runner: ScriptRunner, text: str) -> None: def _on_start_moving(self, script_runner: ScriptRunner) -> None: angle = script_runner.current_measurement.angle if isinstance(angle, float): - angle = f"{round(angle)}°" + angle = f"{angle:.1f}°" self._update(script_runner, f"Moving to {angle}") def _on_start_measuring(self, script_runner: ScriptRunner) -> None: diff --git a/src/frog/gui/measure_script/sequence_widget.py b/src/frog/gui/measure_script/sequence_widget.py index 8a4313ab..fc025e7c 100644 --- a/src/frog/gui/measure_script/sequence_widget.py +++ b/src/frog/gui/measure_script/sequence_widget.py @@ -6,11 +6,11 @@ from PySide6.QtWidgets import ( QAbstractItemView, QButtonGroup, + QDoubleSpinBox, QGroupBox, QHBoxLayout, QMessageBox, QPushButton, - QSpinBox, QTableView, QVBoxLayout, QWidget, @@ -154,7 +154,7 @@ def data( self._sequence[index.row()], SequenceModel._COLUMNS[index.column()] ) if isinstance(value, float): - return f"{value:.0f}°" + return f"{value:.1f}°" return value def headerData( @@ -223,10 +223,12 @@ def __init__(self, sequence: SequenceWidget) -> None: # Add button and spinbox for going to a specific angle. Put them next to each # other on the same row. goto_layout = QHBoxLayout() - self.angle = QSpinBox() + self.angle = QDoubleSpinBox() self.angle.setSuffix("°") - self.angle.setMinimum(0) - self.angle.setMaximum(359) + self.angle.setDecimals(1) + self.angle.setSingleStep(0.1) + self.angle.setMinimum(0.0) + self.angle.setMaximum(359.9) self.goto = QPushButton("GOTO") self.goto.clicked.connect(self._goto_clicked) goto_layout.addWidget(self.angle) diff --git a/src/frog/gui/stepper_motor_view.py b/src/frog/gui/stepper_motor_view.py index 387cce17..f1fca61f 100644 --- a/src/frog/gui/stepper_motor_view.py +++ b/src/frog/gui/stepper_motor_view.py @@ -4,7 +4,13 @@ from pubsub import pub from PySide6.QtCore import Qt -from PySide6.QtWidgets import QButtonGroup, QGridLayout, QLabel, QPushButton, QSpinBox +from PySide6.QtWidgets import ( + QButtonGroup, + QDoubleSpinBox, + QGridLayout, + QLabel, + QPushButton, +) from frog.config import ANGLE_PRESET_NAMES, STEPPER_MOTOR_TOPIC from frog.gui.device_panel import DevicePanel @@ -33,8 +39,10 @@ def __init__(self) -> None: layout.addWidget(btn, row, col) # We also have a way for users to move the mirror to an angle of their choice - self.angle = QSpinBox() - self.angle.setMaximum(359) + self.angle = QDoubleSpinBox() + self.angle.setDecimals(1) + self.angle.setSingleStep(0.1) + self.angle.setMaximum(359.9) self.goto = self._add_checkable_button("GOTO") layout.addWidget(self.angle, 1, 2) @@ -88,9 +96,9 @@ def _update_mirror_position_display(self, moved_to: float) -> None: If angle corresponds to a preset, show the associated name as well as the value. """ - text = f"{round(moved_to)}°" + text = f"{moved_to:.1f}°" if preset := next( - (k for k, v in self.angle_presets.items() if round(v) == round(moved_to)), + (k for k, v in self.angle_presets.items() if abs(v - moved_to) <= 0.05), None, ): text += f" ({preset})" diff --git a/tests/gui/measure_script/test_script_run_dialog.py b/tests/gui/measure_script/test_script_run_dialog.py index 2787d3c6..a9dd683c 100644 --- a/tests/gui/measure_script/test_script_run_dialog.py +++ b/tests/gui/measure_script/test_script_run_dialog.py @@ -116,7 +116,7 @@ def test_update( ) -@pytest.mark.parametrize("angle,angle_str", ((90.0, "90°"), ["zenith"] * 2)) +@pytest.mark.parametrize("angle,angle_str", ((90.0, "90.0°"), ["zenith"] * 2)) def test_on_start_moving( angle: float | str, angle_str: str, diff --git a/tests/gui/measure_script/test_sequence_widget.py b/tests/gui/measure_script/test_sequence_widget.py index e06d46cd..2e7fa328 100644 --- a/tests/gui/measure_script/test_sequence_widget.py +++ b/tests/gui/measure_script/test_sequence_widget.py @@ -219,18 +219,16 @@ def test_add_buttons(preset: str, count: int, widget: SequenceWidget) -> None: "angle,count", ( (angle, count) - for angle in (-90, 0, 1, 90, 180, 270, 359, 360) + for angle in (0.0, 0.1, 1.0, 90.5, 180.0, 270.3, 359.9) for count in range(1, 4) ), ) -def test_add_buttons_goto(angle: int, count: int, widget: SequenceWidget) -> None: +def test_add_buttons_goto(angle: float, count: int, widget: SequenceWidget) -> None: """Test the GOTO button in the AddButtons panel.""" - LIMS = (0, 359) buttons = AddButtons(widget) buttons.angle.setValue(angle) buttons.count.count.setValue(count) with patch.object(widget, "add_instruction") as add_mock: buttons.goto.click() - clamped_angle = max(LIMS[0], min(LIMS[1], angle)) - add_mock.assert_called_once_with(float(clamped_angle), count) + add_mock.assert_called_once_with(angle, count) diff --git a/tests/gui/test_stepper_motor_view.py b/tests/gui/test_stepper_motor_view.py index 651e1f8f..8a978e68 100644 --- a/tests/gui/test_stepper_motor_view.py +++ b/tests/gui/test_stepper_motor_view.py @@ -59,7 +59,7 @@ def test_goto_clicked(sendmsg_mock: MagicMock, qtbot: QtBot) -> None: control = StepperMotorControl() with patch.object(control.angle, "value") as angle_mock: - angle_mock.return_value = 123 + angle_mock.return_value = 123.0 # The motor should be stopped then moved to 123° control._preset_clicked(control.goto) @@ -82,7 +82,7 @@ def test_update_mirror_position_display(qtbot: QtBot) -> None: control._update_preset_angles({"zenith": 180.0}) control._update_mirror_position_display(moved_to=180.0) - assert control.mirror_position_display.text() == "180\u00b0 (zenith)" + assert control.mirror_position_display.text() == "180.0\u00b0 (zenith)" control._update_mirror_position_display(moved_to=12.34) - assert control.mirror_position_display.text() == "12\u00b0" + assert control.mirror_position_display.text() == "12.3\u00b0"