diff --git a/bec_widgets/widgets/control/scan_control/scan_group_box.py b/bec_widgets/widgets/control/scan_control/scan_group_box.py index 9a51a0d9..7d0d3826 100644 --- a/bec_widgets/widgets/control/scan_control/scan_group_box.py +++ b/bec_widgets/widgets/control/scan_control/scan_group_box.py @@ -281,6 +281,17 @@ class ScanGroupBox(QGroupBox): selected_devices_str = " ".join(self.selected_devices.values()) self.device_selected.emit(selected_devices_str.strip()) + def remove_all_widget_bundles(self): + """Remove every widget bundle from the scan control layout.""" + for widget in list(self.widgets): + if isinstance(widget, DeviceLineEdit): + self.selected_devices.pop(widget, None) + widget.close() + widget.deleteLater() + self.layout.removeWidget(widget) + self.widgets.clear() + self.device_selected.emit("") + @Property(bool) def hide_add_remove_buttons(self): return self._hide_add_remove_buttons @@ -349,10 +360,21 @@ class ScanGroupBox(QGroupBox): self._set_kwarg_parameters(parameters) def _set_arg_parameters(self, parameters: list): - while len(parameters) != len(self.widgets): - self.add_widget_bundle() - for i, parameter in enumerate(parameters): - WidgetIO.set_value(self.widgets[i], parameter) + self.remove_all_widget_bundles() + if not parameters: + return + + inputs_per_bundle = len(self.inputs) + if inputs_per_bundle == 0: + return + + bundles_needed = -(-len(parameters) // inputs_per_bundle) + + for row in range(1, bundles_needed + 1): + self.add_input_widgets(self.inputs, row) + + for i, value in enumerate(parameters): + WidgetIO.set_value(self.widgets[i], value) def _set_kwarg_parameters(self, parameters: dict): for widget in self.widgets: diff --git a/tests/unit_tests/test_scan_control.py b/tests/unit_tests/test_scan_control.py index ab9842c1..5248b995 100644 --- a/tests/unit_tests/test_scan_control.py +++ b/tests/unit_tests/test_scan_control.py @@ -558,3 +558,31 @@ def test_scan_metadata_is_connected(scan_control): "test key 1": "test value 1", "test key 2": "test value 2", } + + +def test_restore_parameters_with_fewer_arg_bundles(scan_control, qtbot): + """ + Ensure that when more argument bundles are present than exist in the + stored history, restoring parameters regenerates the arg box to the + correct (smaller) size and sets the values properly. + This is a check for the previous infinite loop bug. + """ + # Select the scan type that has history with only one arg bundle + scan_control.comboBox_scan_selection.setCurrentText("line_scan") + + # Manually add bundles so we end up with three rows + while scan_control.arg_box.count_arg_rows() < 3: + scan_control.arg_box.add_widget_bundle() + assert scan_control.arg_box.count_arg_rows() == 3 + + # Trigger restore of parameters from history + scan_control.toggle.checked = True + qtbot.wait(200) + + # After restore, arg_box should have only one bundle (the history size) + assert scan_control.arg_box.count_arg_rows() == 1 + + # Verify that the restored parameter values match the history + args, kwargs = scan_control.get_scan_parameters(bec_object=False) + assert args == ["samx", 0.0, 2.0] + assert kwargs["steps"] == 10