def test_filtered_list_changing_container_under_changes_retains_order( self): # the bug was that if list model is under a change and items are only # being rearranged (easy to occur with dependent list being sorted differently) # then there is no way to detect that it is not sorted anymore so it proceeds # as if it is already sorted properly. l = ListModel.ListModel("items") l.append_item("3") l.append_item("1") l.append_item("4") l.append_item("2") l2 = ListModel.ListModel("items") l2.append_item("4") l2.append_item("1") l2.append_item("2") l2.append_item("3") l3 = ListModel.FilteredListModel(container=l, items_key="items") self.assertEqual(["3", "1", "4", "2"], l3.items) l4 = ListModel.FilteredListModel(container=l3, items_key="items") self.assertEqual(["3", "1", "4", "2"], l4.items) l4.begin_change() l3.begin_change() l3.filter = ListModel.Filter(True) l3.end_change() l4.end_change() l4.begin_change() l3.begin_change() l3.container = l2 l3.end_change() l4.end_change() self.assertEqual(["4", "1", "2", "3"], l3.items) self.assertEqual(["4", "1", "2", "3"], l4.items)
def test_flattened_model_with_empty_master_item_closes_properly(self): l = ListModel.ListModel("as") bs1 = ListModel.ListModel("bs") bs1.append_item("11") bs2 = ListModel.ListModel("bs") bs3 = ListModel.ListModel("bs") bs3.append_item("31") l.append_item(bs1) l.append_item(bs2) l.append_item(bs3) f = ListModel.FlattenedListModel(container=l, master_items_key="as", child_items_key="bs", items_key="cs") with contextlib.closing(f): pass
def test_flattened_model_initializes_properly(self): l = ListModel.ListModel("as") bs1 = ListModel.ListModel("bs") bs1.append_item("11") bs1.append_item("12") bs2 = ListModel.ListModel("bs") bs3 = ListModel.ListModel("bs") bs3.append_item("31") bs3.append_item("32") bs3.append_item("33") l.append_item(bs1) l.append_item(bs2) l.append_item(bs3) f = ListModel.FlattenedListModel(container=l, master_items_key="as", child_items_key="bs", items_key="cs") self.assertEqual(["11", "12", "31", "32", "33"], f.cs)
def slow_test_threaded_filtered_model_updates(self): for _ in range(1000): list_model = ListModel.ListModel("data_items") filtered_data_items = ListModel.FilteredListModel(items_key="data_items") data_items = list() cc = 30 for _ in range(cc): data_item = DataItem.DataItem(numpy.zeros((16, 16), numpy.uint32)) data_items.append(data_item) c1 = [n for n in range(cc) if random.randint(0,100) > 50] def is_live_filter(data_item): return data_items.index(data_item) in c1 filtered_data_items.container = list_model filtered_data_items.sort_key = lambda x: data_items.index(x) selection = Selection.IndexedSelection() filtered_data_items2 = ListModel.FilteredListModel(items_key="data_items", container=filtered_data_items, selection=selection) filtered_data_items2.filter = ListModel.PredicateFilter(is_live_filter) finished = threading.Event() def update_randomly(): for _ in range(cc): data_item = random.choice(filtered_data_items._get_master_items()) data_item.data_item_changed_event.fire() finished.set() list_model.insert_item(0, data_items[0]) threading.Thread(target = update_randomly).start() for index in range(1, cc): list_model.insert_item(index, data_items[index]) finished.wait() filtered_data_items2.close() filtered_data_items.close()
def __init__(self): self.__config_file = None # the active video sources (hardware sources). this list is updated when a video camera device is registered or # unregistered with the hardware source manager. self.video_sources = ListModel.ListModel() # the list of instances of video cameras. this is similar to the video sources but is the devices plus settings # for the device. some devices might not have instances if the factory to create the instance hasn't been # registered yet. self.__instances = list() # the list of video device factories. this is populated by responding to the registry messages. self.__video_device_factories = list() def component_registered(component, component_types): if "video_device_factory" in component_types: if not component in self.__video_device_factories: self.__video_device_factories.append(component) self.__make_video_devices() def component_unregistered(component, component_types): if "video_device_factory" in component_types: if component in self.__video_device_factories: self.__video_device_factories.remove(component) self.__component_registered_listener = Registry.listen_component_registered_event( component_registered) self.__component_unregistered_listener = Registry.listen_component_unregistered_event( component_unregistered) for component in Registry.get_components_by_type( "video_device_factory"): component_registered(component, {"video_device_factory"})
def test_filtered_list_sends_begin_end_changes_for_grouped_insert_and_remove( self): l = ListModel.ListModel("items") l.append_item("3") l.append_item("1") l.append_item("4") l.append_item("2") l2 = ListModel.FilteredListModel(container=l, items_key="items") l2.sort_key = lambda x: x begin_changes_count = 0 end_changes_count = 0 def begin_changes(key): nonlocal begin_changes_count begin_changes_count += 1 def end_changes(key): nonlocal end_changes_count end_changes_count += 1 with l2.begin_changes_event.listen( begin_changes), l2.end_changes_event.listen(end_changes): with l2.changes(): l.insert_item(0, "5") l.insert_item(0, "6") l.remove_item(0) l.remove_item(0) self.assertEqual(1, begin_changes_count) self.assertEqual(1, end_changes_count)
def test_mapped_list_sends_begin_end_changes_for_single_insert_and_remove( self): l = ListModel.ListModel("items") l.append_item("3") l.append_item("1") l.append_item("4") l.append_item("2") l1 = ListModel.FilteredListModel(container=l, master_items_key="items", items_key="mitems") l1.sort_key = lambda x: x l2 = ListModel.MappedListModel(container=l1, master_items_key="mitems", items_key="items") begin_changes_count = 0 end_changes_count = 0 def begin_changes(key): nonlocal begin_changes_count begin_changes_count += 1 def end_changes(key): nonlocal end_changes_count end_changes_count += 1 with l2.begin_changes_event.listen( begin_changes), l2.end_changes_event.listen(end_changes): l.insert_item(0, "5") l.remove_item(0) self.assertEqual(2, begin_changes_count) self.assertEqual(2, end_changes_count)
def test_random_filtered_model_updates(self): list_model = ListModel.ListModel("data_items") filtered_data_items = ListModel.FilteredListModel(items_key="data_items") filtered_data_items.container = list_model data_items = list() cc = 30 for _ in range(cc): data_item = DataItem.DataItem(numpy.zeros((16, 16), numpy.uint32)) list_model.insert_item(0, data_item) data_items.append(data_item) selection = Selection.IndexedSelection() filtered_data_items2 = ListModel.FilteredListModel(items_key="data_items", container=filtered_data_items, selection=selection) import random for xx in range(10): c1 = [n for n in range(cc)] c2 = [n for n in range(cc) if random.randint(0,100) > 20] random.shuffle(c1) random.shuffle(c2) def is_live_filter(data_item): return data_items.index(data_item) in c1 def is_live_filter2(data_item): return data_items.index(data_item) in c2 filtered_data_items.sort_key = lambda x: data_items.index(x) with filtered_data_items.changes(): filtered_data_items.filter = ListModel.PredicateFilter(is_live_filter) filtered_data_items.filter = ListModel.PredicateFilter(is_live_filter2) self.assertEqual(set(c2), set([data_items.index(d) for d in filtered_data_items2.items])) for data_item in data_items: data_item.close()
def test_initial_mapped_model_values_are_correct(self): l = ListModel.ListModel("items") l.append_item(A("1")) l.append_item(A("2")) l2 = ListModel.MappedListModel(container=l, master_items_key="items", items_key="itemsb", map_fn=B) self.assertEqual([b.s for b in map(B, l.items)], [b.s for b in l2.items]) self.assertEqual(l2.itemsb, l2.items) self.assertEqual("2_B", l2.items[1].s)
def create_objects(self, name: str, items, label: str = None) -> ComputationVariable: list_model = ListModel.ListModel(items=items) variable = ComputationVariable(name, objects=list_model, label=label) self.add_variable(variable) return variable
def read_from_dict(self, properties: dict) -> None: # used for persistence # ensure that value_type is read first value_type_property = self._get_persistent_property("value_type") value_type_property.read_from_dict(properties) super().read_from_dict(properties) if self.object_specifiers: self.__objects_model = ListModel.ListModel( items=self.object_specifiers)
def test_mapped_model_selection_after_insert_are_correct(self): l = ListModel.ListModel("items") l.append_item(A("1")) l.append_item(A("2")) l2 = ListModel.MappedListModel(container=l, master_items_key="items", items_key="itemsb", map_fn=B) s = l2.make_selection() s.add(0) s.add(1) l.insert_item(1, A("1.5")) self.assertEqual({0, 2}, s.indexes)
def test_should_be_able_to_get_items_from_list_binding(self): list_model = ListModel.ListModel("items") list_model.insert_item(0, "zero") list_model.insert_item(1, "one") list_model.insert_item(2, "two") binding = Binding.ListBinding(list_model, "items") items = binding.items self.assertEqual(len(items), 3) self.assertEqual(items[2], "two") list_model.insert_item(0, "negative") self.assertEqual(len(items), 4) self.assertEqual(items[3], "two")
def test_inserting_items_into_model_index0_without_sort_key_puts_them_in_same_order(self): list_model = ListModel.ListModel("data_items") filtered_data_items = ListModel.FilteredListModel(items_key="data_items") filtered_data_items.container = list_model data_items = list() for index, value in enumerate(TestDataItemsModelModule.values): data_item = DataItem.DataItem(numpy.zeros((16, 16), numpy.uint32)) data_item.title = value list_model.insert_item(TestDataItemsModelModule.indexes[index], data_item) data_items.append(data_item) self.assertEqual([d.title for d in filtered_data_items.items], TestDataItemsModelModule.result) for data_item in data_items: data_item.close()
def test_inserting_items_into_model_index0_with_sort_key_puts_them_in_correct_order(self): list_model = ListModel.ListModel("data_items") filtered_data_items = ListModel.FilteredListModel(items_key="data_items") filtered_data_items.container = list_model filtered_data_items.sort_key = operator.attrgetter("title") data_items = list() for value in TestDataItemsModelModule.values: data_item = DataItem.DataItem(numpy.zeros((16, 16), numpy.uint32)) data_item.title = value list_model.insert_item(0, data_item) data_items.append(data_item) self.assertEqual([d.title for d in filtered_data_items.items], sorted([d.title for d in filtered_data_items.items])) for data_item in data_items: data_item.close()
def test_filtered_list_changing_from_sorted_to_unsorted_retains_order(self): l = ListModel.ListModel("items") l.append_item("3") l.append_item("1") l.append_item("4") l.append_item("2") l2 = ListModel.FilteredListModel(container=l, items_key="items") l2.sort_key = lambda x: x self.assertEqual(["1", "2", "3", "4"], l2.items) l2.filter = ListModel.PredicateFilter(lambda x: x != "4") l2.sort_key = None self.assertEqual(["3", "1", "2"], l2.items) l.remove_item(1) self.assertEqual(["3", "2"], l2.items)
def test_filtered_list_is_sorted(self): l = ListModel.ListModel("items") l.append_item("3") l.append_item("1") l.append_item("4") l.append_item("2") l2 = ListModel.FilteredListModel(container=l, items_key="items") l2.sort_key = lambda x: x l2.mark_changed() self.assertEqual(["1", "2", "3", "4"], l2.items) l.remove_item(1) l.remove_item(1) self.assertEqual(["2", "3"], l2.items) l.insert_item(0, "5") l.insert_item(0, "1") self.assertEqual(["1", "2", "3", "5"], l2.items)
def test_filter_model_inits_with_source_model(self): list_model = ListModel.ListModel("data_items") filtered_data_items = ListModel.FilteredListModel(items_key="data_items") filtered_data_items.container = list_model filtered_data_items.sort_key = operator.attrgetter("title") data_items = list() for value in TestDataItemsModelModule.values: data_item = DataItem.DataItem(numpy.zeros((16, 16), numpy.uint32)) data_item.title = value list_model.insert_item(0, data_item) data_items.append(data_item) self.assertEqual([d.title for d in filtered_data_items.items], sorted([d.title for d in filtered_data_items.items])) selection = Selection.IndexedSelection() filtered_data_items2 = ListModel.FilteredListModel(items_key="data_items", container=filtered_data_items, selection=selection) self.assertEqual([d.title for d in filtered_data_items.items], [d.title for d in filtered_data_items2.items]) for data_item in data_items: data_item.close()
def test_table_widget_handles_pending_updates_in_close(self): from nion.ui import Widgets ui = TestUI.UserInterface() def create_item(item): return ui.create_label_widget(item) widget = Widgets.TableWidget(ui, create_item) list_model = ListModel.ListModel() widget.bind_items(Binding.ListBinding(list_model, "items")) with contextlib.closing(widget): list_model.insert_item(0, "abc") list_model.insert_item(1, "abc") list_model.remove_item(0) self.assertEqual(3, len(widget.pending_queued_tasks)) self.assertEqual(0, len(widget.pending_queued_tasks)) widget.run_pending_keyed_tasks()
def test_inserting_items_into_model_index0_without_sort_key__but_with_filter_puts_them_in_same_order(self): values = ["DEF", "ABC", "GHI", "DFG", "ACD", "GIJ"] indexes = [0, 0, 1, 1, 2, 4] result = ["ABC", "DFG", "ACD", "GHI", "GIJ", "DEF"] list_model = ListModel.ListModel("data_items") filtered_data_items = ListModel.FilteredListModel(items_key="data_items") filtered_data_items.container = list_model filtered_data_items.filter = ListModel.NotFilter(ListModel.StartsWithFilter("title", "D")) data_items = list() for index, value in enumerate(values): data_item = DataItem.DataItem(numpy.zeros((16, 16), numpy.uint32)) data_item.title = value list_model.insert_item(indexes[index], data_item) data_items.append(data_item) self.assertEqual([d.title for d in filtered_data_items.items], [v for v in result if not v.startswith("D")]) for data_item in data_items: data_item.close()
def test_filtered_list_unsorted_retains_order(self): l = ListModel.ListModel("items") l.append_item("3") l.append_item("1") l.append_item("4") l.append_item("2") l2 = ListModel.FilteredListModel(container=l, items_key="items") l2.filter = ListModel.PredicateFilter(lambda x: x != "4") self.assertEqual(["3", "1", "2"], l2.items) l.remove_item(0) self.assertEqual(["1", "2"], l2.items) l.insert_item(0, "3") l.append_item("44") self.assertEqual(["3", "1", "2", "44"], l2.items) l2.begin_change() l.insert_item(0, "5") l.append_item("6") l2.end_change() self.assertEqual(["5", "3", "1", "2", "44", "6"], l2.items)
def __init__(self) -> None: super().__init__() # define our list of shapes, one from each class self.shapes_model = ListModel.ListModel(items=[Rectangle(), Circle(), Interval()]) # define the shape index model self.shape_index_model = Model.PropertyModel(0) # define the shape page model self.shape_page = Model.PropertyModel[str]() def shape_index_changed(p: typing.Optional[str] = None) -> None: self.shape_page.value = self.shapes_model.items[self.shape_index_model.value or 0].type shape_index_changed() # track changes to shape index and update shape page. self.__shape_index_changed = self.shape_index_model.property_changed_event.listen(shape_index_changed)
def test_inserting_and_removing_item_into_binding_notifies_target(self): list_model = ListModel.ListModel("items") binding = Binding.ListBinding(list_model, "items") list_copy = list() def inserter(value: str, index: int) -> None: list_copy.insert(index, value) def remover(index: int) -> None: del list_copy[index] binding.inserter = inserter binding.remover = remover list_model.insert_item(0, "zero") list_model.insert_item(1, "one") self.assertEqual(len(list_copy), 2) self.assertEqual(list_copy[1], "one") list_model.remove_item(0) self.assertEqual(len(list_copy), 1) self.assertEqual(list_copy[0], "one")
def __init__(self) -> None: super().__init__() # define our list of shapes, one from each class self.shapes_model = ListModel.ListModel( items=[Rectangle(), Circle(), Interval()])
def create_panel_widget(self, ui: Facade.UserInterface, document_controller: Facade.DocumentWindow) -> Facade.ColumnWidget: stem_controller_ = typing.cast(stem_controller.STEMController, Registry.get_component("stem_controller")) self.__scan_hardware_source_choice = HardwareSourceChoice.HardwareSourceChoice(ui._ui, "scan_acquisition_hardware_source_id", lambda hardware_source: hardware_source.features.get("is_scanning")) self.__camera_hardware_source_choice = HardwareSourceChoice.HardwareSourceChoice(ui._ui, "scan_acquisition_camera_hardware_source_id", lambda hardware_source: hardware_source.features.get("is_camera")) self.__scan_acquisition_preference_panel = ScanAcquisitionPreferencePanel(self.__scan_hardware_source_choice, self.__camera_hardware_source_choice) self.__scan_hardware_source_stream = HardwareSourceChoice.HardwareSourceChoiceStream(self.__scan_hardware_source_choice).add_ref() self.__camera_hardware_source_stream = HardwareSourceChoice.HardwareSourceChoiceStream(self.__camera_hardware_source_choice).add_ref() def update_context() -> None: scan_hardware_source = typing.cast(scan_base.ScanHardwareSource, self.__scan_hardware_source_choice.hardware_source) scan_context = scan_hardware_source.scan_context if scan_context.is_valid and scan_hardware_source.line_scan_enabled and scan_hardware_source.line_scan_vector: calibration = scan_context.calibration start = Geometry.FloatPoint.make(scan_hardware_source.line_scan_vector[0]) end = Geometry.FloatPoint.make(scan_hardware_source.line_scan_vector[1]) length = int(Geometry.distance(start, end) * scan_context.size.height) max_dim = max(scan_context.size.width, scan_context.size.height) length_str = calibration.convert_to_calibrated_size_str(length, value_range=(0, max_dim), samples=max_dim) line_str = _("Line Scan") self.__roi_description.text = f"{line_str} {length_str} ({length} px)" scan_str = _("Scan (1D)") scan_length = max(self.__scan_width, 1) self.__scan_label_widget.text = f"{scan_str} {scan_length} px" self.__scan_pixels = scan_length self.__scan_specifier.scan_context = copy.deepcopy(scan_context) self.__scan_specifier.size = 1, scan_length self.__scan_specifier.drift_interval_lines = 0 self.__acquire_button._widget.enabled = True elif scan_context.is_valid and scan_hardware_source.subscan_enabled and scan_hardware_source.subscan_region: calibration = scan_context.calibration width = scan_hardware_source.subscan_region.width * scan_context.size.width height = scan_hardware_source.subscan_region.height * scan_context.size.height width_str = calibration.convert_to_calibrated_size_str(width, value_range=(0, scan_context.size.width), samples=scan_context.size.width) height_str = calibration.convert_to_calibrated_size_str(height, value_range=(0, scan_context.size.height), samples=scan_context.size.height) rect_str = _("Subscan") self.__roi_description.text = f"{rect_str} {width_str} x {height_str} ({int(width)} px x {int(height)} px)" scan_str = _("Scan (2D)") scan_width = self.__scan_width scan_height = int(self.__scan_width * height / width) drift_lines = scan_hardware_source.calculate_drift_lines(scan_width, self.__exposure_time_ms_value_model.value / 1000) if scan_hardware_source else 0 drift_str = f" / Drift {drift_lines} lines" if drift_lines > 0 else str() self.__scan_label_widget.text = f"{scan_str} {scan_width} x {scan_height} px" + drift_str self.__scan_pixels = scan_width * scan_height self.__scan_specifier.scan_context = copy.deepcopy(scan_context) self.__scan_specifier.size = scan_height, scan_width self.__scan_specifier.drift_interval_lines = drift_lines self.__acquire_button._widget.enabled = True elif scan_context.is_valid: calibration = scan_context.calibration width = scan_context.size.width height = scan_context.size.height width_str = calibration.convert_to_calibrated_size_str(width, value_range=(0, scan_context.size.width), samples=scan_context.size.width) height_str = calibration.convert_to_calibrated_size_str(height, value_range=(0, scan_context.size.height), samples=scan_context.size.height) data_str = _("Context Scan") self.__roi_description.text = f"{data_str} {width_str} x {height_str} ({int(width)} x {int(height)})" scan_str = _("Scan (2D)") scan_width = self.__scan_width scan_height = int(self.__scan_width * height / width) drift_lines = scan_hardware_source.calculate_drift_lines(scan_width, self.__exposure_time_ms_value_model.value / 1000) if scan_hardware_source else 0 drift_str = f" / Drift {drift_lines} lines" if drift_lines > 0 else str() self.__scan_label_widget.text = f"{scan_str} {scan_width} x {scan_height} px" + drift_str self.__scan_pixels = scan_width * scan_height self.__scan_specifier.scan_context = copy.deepcopy(scan_context) self.__scan_specifier.size = scan_height, scan_width self.__scan_specifier.drift_interval_lines = drift_lines self.__acquire_button._widget.enabled = True else: self.__roi_description.text = _("Scan context not active") self.__scan_label_widget.text = None self.__scan_specifier.scan_context = stem_controller.ScanContext() self.__scan_specifier.size = None self.__scan_specifier.drift_interval_lines = 0 self.__acquire_button._widget.enabled = self.__acquisition_state == SequenceState.scanning # focus will be on the SI data, so enable if scanning self.__scan_pixels = 0 self.__scan_width_widget.text = Converter.IntegerToStringConverter().convert(self.__scan_width) self.__update_estimate() def stem_controller_property_changed(key: str) -> None: if key in ("subscan_state", "subscan_region", "subscan_rotation", "line_scan_state", "line_scan_vector", "drift_channel_id", "drift_region", "drift_settings"): document_controller._document_controller.event_loop.call_soon_threadsafe(update_context) def scan_context_changed() -> None: update_context() self.__stem_controller_property_listener = None self.__scan_context_changed_listener = None if stem_controller_: self.__stem_controller_property_listener = stem_controller_.property_changed_event.listen(stem_controller_property_changed) self.__scan_context_changed_listener = stem_controller_.scan_context_changed_event.listen(scan_context_changed) column = ui.create_column_widget() self.__styles_list_model = ListModel.ListModel(items=[ScanAcquisitionProcessing.SUM_PROJECT, ScanAcquisitionProcessing.NONE]) self.__styles_list_property_model = ListModel.ListPropertyModel(self.__styles_list_model) self.__style_combo_box = ui.create_combo_box_widget(self.__styles_list_property_model.value, item_text_getter=operator.attrgetter("value.display_name")) self.__style_combo_box._widget.set_property("min-width", 100) items_binding = Binding.PropertyBinding(self.__styles_list_property_model, "value") items_binding.source_setter = None self.__style_combo_box._widget.bind_items(items_binding) self.__style_combo_box.current_index = 0 self.__acquire_button = ui.create_push_button_widget(_("Acquire")) self.__roi_description = ui.create_label_widget() self.__scan_width_widget = ui.create_line_edit_widget() self.__exposure_time_widget = ui.create_line_edit_widget() self.__estimate_label_widget = ui.create_label_widget() self.__scan_label_widget = ui.create_label_widget() class ComboBoxWidget: def __init__(self, widget): self.__combo_box_widget = widget @property def _widget(self): return self.__combo_box_widget camera_row = ui.create_row_widget() camera_row.add_spacing(12) camera_row.add(ComboBoxWidget(self.__camera_hardware_source_choice.create_combo_box(ui._ui))) camera_row.add_spacing(12) camera_row.add(self.__style_combo_box) camera_row.add_spacing(12) camera_row.add_stretch() scan_choice_row = ui.create_row_widget() scan_choice_row.add_spacing(12) scan_choice_row.add(ComboBoxWidget(self.__scan_hardware_source_choice.create_combo_box(ui._ui))) scan_choice_row.add_spacing(12) scan_choice_row.add_stretch() roi_size_row = ui.create_row_widget() roi_size_row.add_spacing(12) roi_size_row.add(self.__roi_description) roi_size_row.add_spacing(12) roi_size_row.add_stretch() scan_spacing_pixels_row = ui.create_row_widget() scan_spacing_pixels_row.add_spacing(12) scan_spacing_pixels_row.add(ui.create_label_widget("Scan Width (pixels)")) scan_spacing_pixels_row.add_spacing(12) scan_spacing_pixels_row.add(self.__scan_width_widget) scan_spacing_pixels_row.add_spacing(12) scan_spacing_pixels_row.add_stretch() eels_exposure_row = ui.create_row_widget() eels_exposure_row.add_spacing(12) eels_exposure_row.add(ui.create_label_widget("Camera Exposure Time (ms)")) eels_exposure_row.add_spacing(12) eels_exposure_row.add(self.__exposure_time_widget) eels_exposure_row.add_spacing(12) eels_exposure_row.add_stretch() scan_row = ui.create_row_widget() scan_row.add_spacing(12) scan_row.add(self.__scan_label_widget) scan_row.add_stretch() estimate_row = ui.create_row_widget() estimate_row.add_spacing(12) estimate_row.add(self.__estimate_label_widget) estimate_row.add_stretch() acquire_sequence_button_row = ui.create_row_widget() acquire_sequence_button_row.add(self.__acquire_button) acquire_sequence_button_row.add_stretch() if self.__scan_hardware_source_choice.hardware_source_count > 1: column.add_spacing(8) column.add(scan_choice_row) column.add_spacing(8) column.add(camera_row) column.add_spacing(8) column.add(roi_size_row) column.add_spacing(8) column.add(scan_spacing_pixels_row) column.add_spacing(8) column.add(eels_exposure_row) column.add_spacing(8) column.add(scan_row) column.add_spacing(8) column.add(estimate_row) column.add_spacing(8) column.add(acquire_sequence_button_row) column.add_spacing(8) column.add_stretch() def camera_hardware_source_changed(hardware_source): self.disconnect_camera_hardware_source() if hardware_source: self.connect_camera_hardware_source(hardware_source) if hardware_source.features.get("has_masked_sum_option"): self.__styles_list_model.items = [ScanAcquisitionProcessing.SUM_PROJECT, ScanAcquisitionProcessing.NONE, ScanAcquisitionProcessing.SUM_MASKED] else: self.__styles_list_model.items = [ScanAcquisitionProcessing.SUM_PROJECT, ScanAcquisitionProcessing.NONE] self.__camera_hardware_changed_event_listener = self.__camera_hardware_source_choice.hardware_source_changed_event.listen(camera_hardware_source_changed) camera_hardware_source_changed(self.__camera_hardware_source_choice.hardware_source) def style_current_item_changed(current_item): self.__update_estimate() self.__style_combo_box.on_current_item_changed = style_current_item_changed def scan_width_changed(text: str) -> None: scan_width = Converter.IntegerToStringConverter().convert_back(text) if text else 1 scan_width = max(scan_width, 1) if scan_width != self.__scan_width: self.__scan_width = scan_width update_context() self.__scan_width_widget.request_refocus() self.__scan_width_widget.on_editing_finished = scan_width_changed def acquisition_state_changed(acquisition_state: SequenceState) -> None: self.__acquisition_state = acquisition_state async def update_button_text(text: str) -> None: self.__acquire_button.text = text update_context() # update the cancel button if acquisition_state == SequenceState.idle: self.__scan_acquisition_controller = None self.__acquisition_state_changed_event_listener.close() self.__acquisition_state_changed_event_listener = None document_controller._document_window.event_loop.create_task(update_button_text(_("Acquire"))) else: document_controller._document_window.event_loop.create_task(update_button_text(_("Cancel"))) def acquire_sequence() -> None: if self.__scan_acquisition_controller: if self.__scan_acquisition_controller: self.__scan_acquisition_controller.cancel() else: if self.__scan_hardware_source_choice.hardware_source: scan_hardware_source = self.__api.get_hardware_source_by_id(self.__scan_hardware_source_choice.hardware_source.hardware_source_id, version="1.0") else: scan_hardware_source = None if self.__camera_hardware_source_choice.hardware_source: camera_hardware_source = self.__api.get_hardware_source_by_id(self.__camera_hardware_source_choice.hardware_source.hardware_source_id, version="1.0") else: camera_hardware_source = None if scan_hardware_source and camera_hardware_source: self.__scan_acquisition_controller = ScanAcquisitionController(self.__api, document_controller, scan_hardware_source, camera_hardware_source, self.__scan_specifier) self.__acquisition_state_changed_event_listener = self.__scan_acquisition_controller.acquisition_state_changed_event.listen(acquisition_state_changed) self.__scan_acquisition_controller.start(self.__style_combo_box.current_item) self.__acquire_button.on_clicked = acquire_sequence self.__update_estimate() update_context() return column