feat: pending color while typing in Experiment configuration values
Values inside the Experiment configuration banner now show the same pending color as the motor move boxes while the typed text differs from the applied value; Enter (or focus-out) commits as before and clears it. Opt-in via NumberLineEdit(track_pending=True) because MotorMoveGroup owns the movestate property on its registered boxes; reuses the existing movestate QSS, so no new styling. The Set Energy spinbox marks pending until Change Energy is clicked, since its apply gate is the button. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,12 +11,13 @@ import pytest
|
||||
from aarecommon.math.coordinate import Coordinate, SmargonCoordinate
|
||||
from aarecommon.math.diffraction_geometry import DiffractionGeometry
|
||||
from aarecommon.models.models import SampleGeometryModel
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
from aare.gui.panels.data_collection_settings import DataCollectionSettings
|
||||
from aare.gui.panels.raster_data_collection import RasterDataCollectionPanel
|
||||
from aare.gui.panels.rotation_data_collection import RotationDataCollectionPanel
|
||||
from aare.gui.scan_logic.raster_grid_manager import RasterGridManager
|
||||
from aare.gui.widgets.number_line_edit import DbOverrideLineEdit
|
||||
from aare.gui.widgets.number_line_edit import DbOverrideLineEdit, NumberLineEdit
|
||||
|
||||
|
||||
def _edit(field: DbOverrideLineEdit, text: str):
|
||||
@@ -267,3 +268,101 @@ def test_auto_center_fires_on_mount_only_when_armed(settings_panel):
|
||||
settings_panel._track_sample(None)
|
||||
settings_panel._track_sample(4)
|
||||
assert len(clicks) == 3
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pending color while typing (movestate property, committed on Enter/focus-out)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _type(qtbot, box, text):
|
||||
box.clear()
|
||||
qtbot.keyClicks(box, text)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tracked_box(qtbot):
|
||||
box = NumberLineEdit(-720, 720, default=100.0, decimals=2, track_pending=True)
|
||||
qtbot.addWidget(box)
|
||||
return box
|
||||
|
||||
|
||||
def test_typing_marks_pending_and_enter_commits(tracked_box, qtbot):
|
||||
seen = []
|
||||
tracked_box.newValue.connect(seen.append)
|
||||
_type(qtbot, tracked_box, "300")
|
||||
assert tracked_box.property("movestate") == "pending"
|
||||
assert not seen # nothing is applied until Enter/focus-out
|
||||
qtbot.keyClick(tracked_box, Qt.Key.Key_Return)
|
||||
assert seen == [300.0]
|
||||
assert tracked_box.property("movestate") == ""
|
||||
|
||||
|
||||
def test_typing_back_the_applied_value_cancels_pending(tracked_box, qtbot):
|
||||
_type(qtbot, tracked_box, "300")
|
||||
qtbot.keyClick(tracked_box, Qt.Key.Key_Return)
|
||||
_type(qtbot, tracked_box, "300") # same as what is applied now
|
||||
assert tracked_box.property("movestate") == ""
|
||||
|
||||
|
||||
def test_incomplete_entry_is_pending(tracked_box, qtbot):
|
||||
_type(qtbot, tracked_box, "-") # not a number (yet)
|
||||
assert tracked_box.property("movestate") == "pending"
|
||||
|
||||
|
||||
def test_untracked_box_never_touches_movestate(qtbot):
|
||||
# MotorMoveGroup owns movestate on the boxes it registers; the default
|
||||
# NumberLineEdit must therefore stay away from the property entirely.
|
||||
box = NumberLineEdit(-720, 720, default=100.0, decimals=2)
|
||||
qtbot.addWidget(box)
|
||||
_type(qtbot, box, "300")
|
||||
assert box.property("movestate") is None
|
||||
|
||||
|
||||
def test_programmatic_update_clears_pending(tracked_box, qtbot):
|
||||
_type(qtbot, tracked_box, "300")
|
||||
tracked_box.force_update_value(120.0)
|
||||
assert tracked_box.property("movestate") == ""
|
||||
_type(qtbot, tracked_box, "300")
|
||||
tracked_box.update_value(500.0)
|
||||
assert tracked_box.property("movestate") == ""
|
||||
|
||||
|
||||
def test_db_override_typing_pending_until_commit(qapp, qtbot):
|
||||
w = DbOverrideLineEdit(0, 1000, default=200.0, decimals=2)
|
||||
qtbot.addWidget(w)
|
||||
_type(qtbot, w.editor, "300")
|
||||
assert w.editor.property("movestate") == "pending"
|
||||
qtbot.keyClick(w.editor, Qt.Key.Key_Return)
|
||||
assert w.editor.property("movestate") == ""
|
||||
assert w.value == 300.0
|
||||
assert w.source() == DbOverrideLineEdit.SOURCE_MINE
|
||||
|
||||
|
||||
def test_db_override_source_toggle_clears_pending(qapp, qtbot):
|
||||
w = DbOverrideLineEdit(0, 1000, default=200.0, decimals=2)
|
||||
qtbot.addWidget(w)
|
||||
_type(qtbot, w.editor, "300") # typing, no commit
|
||||
assert w.editor.property("movestate") == "pending"
|
||||
# a panel refresh (radio toggle, DB push) discards the uncommitted text
|
||||
w.set_source(DbOverrideLineEdit.SOURCE_DB, emit=False)
|
||||
assert w.editor.property("movestate") == ""
|
||||
assert w.value == 200.0
|
||||
|
||||
|
||||
def test_energy_spin_pending_until_change_energy(settings_panel):
|
||||
box = settings_panel.energy_spin.lineEdit()
|
||||
settings_panel.energy_spin.setValue(12.4)
|
||||
assert box.property("movestate") == "pending"
|
||||
|
||||
sent = []
|
||||
settings_panel.change_energy.connect(sent.append)
|
||||
settings_panel.change_energy_button.click()
|
||||
assert sent and sent[-1] == pytest.approx(12400.0)
|
||||
assert box.property("movestate") == ""
|
||||
|
||||
# dialing back to the last sent value clears without the button
|
||||
settings_panel.energy_spin.setValue(12.5)
|
||||
assert box.property("movestate") == "pending"
|
||||
settings_panel.energy_spin.setValue(12.4)
|
||||
assert box.property("movestate") == ""
|
||||
|
||||
Reference in New Issue
Block a user