diff --git a/nion/swift/Inspector.py b/nion/swift/Inspector.py index 2e6fcaff..8b926d7c 100755 --- a/nion/swift/Inspector.py +++ b/nion/swift/Inspector.py @@ -3195,12 +3195,15 @@ def __create_position_and_shape_ui(self) -> Declarative.UIDescriptionResult: return self.__shape_and_pos_func() -class GraphicsCalibrationHandler(Declarative.Handler): - def __init__(self, document_controller: DocumentController.DocumentController, display_item: DisplayItem.DisplayItem): +class GraphicsSectionHandler(Declarative.Handler): + def __init__(self, document_controller: DocumentController.DocumentController, + display_item: DisplayItem.DisplayItem, + graphics_model: ListModel.ObservedListModel[DisplayItem.DisplayLayer]): super().__init__() - self.__document_controller = document_controller self.__display_item = display_item + self._graphics_model = graphics_model + self._graphic_handlers: list[GraphicsInspectorHandler] = [] calibration_styles = display_item.calibration_styles self.__display_calibration_style_options = [calibration_style.label for calibration_style in calibration_styles] @@ -3212,19 +3215,29 @@ def __init__(self, document_controller: DocumentController.DocumentController, d self._current_calibration_index_model = Model.PropertyModel( self.__display_calibration_style_reverse_map.get(self.__display_item.calibration_style_id)) self.__calibration_style_listener = self.__display_item.display_property_changed_event.listen( - ReferenceCounting.weak_partial(GraphicsCalibrationHandler.__update_calibration_id, self) - ) + ReferenceCounting.weak_partial(GraphicsSectionHandler.__update_calibration_id, self)) u = Declarative.DeclarativeUI() - - self.ui_view = display_calibrations_row = u.create_row( - u.create_label(text=_("Display"), width=60, text_alignment_vertical="center"), - u.create_combo_box(items=self.__display_calibration_style_options, - current_index="@binding(_current_calibration_index_model.value)", - on_current_index_changed="_change_calibration_style_option"), + self.ui_view = u.create_column( + u.create_column(items="_graphics_model.items", item_component_id="graphic", spacing=4), + u.create_row( + u.create_label(text=_("Display"), width=60, text_alignment_vertical="center"), + u.create_combo_box(items=self.__display_calibration_style_options, + current_index="@binding(_current_calibration_index_model.value)", + on_current_index_changed="_change_calibration_style_option"), + u.create_stretch() + ), u.create_stretch() ) + def create_handler(self, component_id: str, container: typing.Optional[Symbolic.ComputationVariable] = None, item: typing.Any = None, **kwargs: typing.Any) -> typing.Optional[Declarative.HandlerLike]: + if component_id == "graphic": + graphic = typing.cast(Graphics.Graphic, item) + handler = GraphicsInspectorHandler(self.__document_controller, self.__display_item, graphic) + self._graphic_handlers.append(handler) + return handler + return None + def _change_calibration_style_option(self, widget: Declarative.UIWidget, current_index: int) -> None: self.__display_item.calibration_style_id = self.__display_calibration_style_ids[current_index] @@ -3242,20 +3255,12 @@ class GraphicsInspectorSection(InspectorSection): def __init__(self, document_controller: DocumentController.DocumentController, display_item: DisplayItem.DisplayItem, selected_only: bool = False) -> None: super().__init__(document_controller.ui, "graphics", _("Graphics")) self.widget_id = "graphics_inspector_section" - graphics = getattr(display_item, "selected_graphics" if selected_only else "graphics") - - handlers = [] - for index, graphic in enumerate(graphics): - graphic_handler = GraphicsInspectorHandler(document_controller, display_item, graphic) - graphic_widget = Declarative.DeclarativeWidget(document_controller.ui, document_controller.event_loop, graphic_handler) - self.add_widget_to_content(graphic_widget) - handlers.append(graphic_handler) - - self._handlers = handlers - self._calibration_handler = GraphicsCalibrationHandler(document_controller, display_item) - - calibration_widget = Declarative.DeclarativeWidget(document_controller.ui, document_controller.event_loop, self._calibration_handler) - self.add_widget_to_content(calibration_widget) + self.__document_controller = document_controller + self.__display_item = display_item + graphics_model = ListModel.ObservedListModel[DisplayItem.DisplayLayer](self.__display_item, "selected_graphics" if selected_only else "graphics") + self._handler = GraphicsSectionHandler(self.__document_controller, self.__display_item, graphics_model) + self.__widget = Declarative.DeclarativeWidget(self.__document_controller.ui, self.__document_controller.event_loop, self._handler) + self.add_widget_to_content(self.__widget) class ChangeComputationVariableCommand(Undo.UndoableCommand): diff --git a/nion/swift/test/Inspector_test.py b/nion/swift/test/Inspector_test.py index ca9ad20f..4eb575c0 100755 --- a/nion/swift/test/Inspector_test.py +++ b/nion/swift/test/Inspector_test.py @@ -191,7 +191,7 @@ def test_graphic_inspector_section_follows_spatial_calibration_change(self): display_panel.set_display_panel_display_item(display_item) document_controller.periodic() # needed to build the inspector inspector_panel = document_controller.find_dock_panel("inspector-panel") - point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] x_model = point_handler._point_position_x_model self.assertEqual(x_model.value, "128.0 mm") display_item.data_item.set_dimensional_calibration(1, Calibration.Calibration(units="mmm")) @@ -216,7 +216,7 @@ def test_changing_calibration_style_to_calibrated_displays_correct_values(self): document_controller.periodic() # needed to build the inspector inspector_panel = document_controller.find_dock_panel("inspector-panel") # check the values - point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] x_model = point_handler._point_position_x_model y_model = point_handler._point_position_y_model self.assertEqual(x_model.value, "0.0 mm") @@ -240,7 +240,7 @@ def test_graphic_inspector_section_displays_sensible_units(self): display_panel.set_display_panel_display_item(display_item) document_controller.periodic() # needed to build the inspector inspector_panel = document_controller.find_dock_panel("inspector-panel") - point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] x_model = point_handler._point_position_x_model # check the values display_item.data_item.set_dimensional_calibration(1, Calibration.Calibration(scale=math.sqrt(2.0), units="mm")) @@ -279,7 +279,7 @@ def test_graphic_inspector_display_calibrated_length_units(self): data_item.set_dimensional_calibration(0, Calibration.Calibration(units="mm")) data_item.set_dimensional_calibration(1, Calibration.Calibration(units="mm")) document_controller.periodic() # needed to update the inspector - line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] self.assertEqual(line_handler._length_model.value, "223.607 mm") # sqrt(100*100 + 200*200) def test_graphic_inspector_sets_calibrated_length_units(self): @@ -304,7 +304,7 @@ def test_graphic_inspector_sets_calibrated_length_units(self): data_item.set_dimensional_calibration(1, Calibration.Calibration(units="mm")) document_controller.periodic() # needed to update the inspector length_str = "{0:g}".format(math.sqrt(100 * 100 + 200 * 200)) - line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] length_model = line_handler._length_model length_model.value = length_str self.assertAlmostEqual(line_region.end[0], 1.0, 3) @@ -329,7 +329,7 @@ def test_graphic_inspector_sets_calibrated_angle_units(self): inspector_panel = document_controller.find_dock_panel("inspector-panel") # check the values document_controller.periodic() # needed to update the inspector - line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] angle_model = line_handler._angle_model self.assertEqual(-45.0, Converter.FloatToStringConverter().convert_back(angle_model.value)) angle_model.value = "45" @@ -356,7 +356,7 @@ def test_graphics_inspector_uses_non_calibrated_units_for_non_uniformly_calibrat line_region.start = (0, 0) line_region.end = (0.4, 0.3) document_controller.periodic() # needed to update the inspector - line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] length_model = line_handler._length_model self.assertEqual("50", length_model.value) length_model.value = "100" @@ -393,7 +393,7 @@ def test_line_profile_inspector_display_calibrated_width_units(self): data_item.set_dimensional_calibration(0, Calibration.Calibration(units="mm")) data_item.set_dimensional_calibration(1, Calibration.Calibration(units="mm")) document_controller.periodic() # needed to update the inspector - line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + line_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] self.assertEqual(line_handler._line_profile_width_model.value, "10.0 mm") def test_float_to_string_converter_strips_units(self): @@ -848,7 +848,7 @@ def test_pixel_center_rounding_correct_on_odd_dimensioned_image(self): # check the values display_item.calibration_style_id = "pixels-center" document_controller.periodic() # needed to build the inspector - point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + point_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] self.assertEqual(point_handler._point_position_x_model.value, "0.0") # x self.assertEqual(point_handler._point_position_y_model.value, "0.0") # y @@ -868,7 +868,7 @@ def test_editing_pixel_width_on_rectangle_adjusts_rectangle_properly(self): inspector_panel = document_controller.find_dock_panel("inspector-panel") display_item.calibration_style_id = "pixels-center" document_controller.periodic() # needed to update the inspector - rectangle_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handlers[0] + rectangle_handler = inspector_panel.column.find_widget_by_id("graphics_inspector_section")._handler._graphic_handlers[0] x_model = rectangle_handler._center_x_model y_model = rectangle_handler._center_y_model width_model = rectangle_handler._width_model @@ -1103,7 +1103,7 @@ def test_spot_graphic_inspector_updates_without_exception(self): document_controller.periodic() graphics_section = inspector_panel.column.find_widget_by_id("graphics_inspector_section") self.assertIsNotNone(graphics_section) - self.assertIn("Spot", (i._graphic_type_model.value for i in graphics_section._handlers)) + self.assertIn("Spot", (i._graphic_type_model.value for i in graphics_section._handler._graphic_handlers)) def test_band_pass_graphic_inspector_updates_without_exception(self): with TestContext.create_memory_context() as test_context: @@ -1121,7 +1121,7 @@ def test_band_pass_graphic_inspector_updates_without_exception(self): document_controller.periodic() graphics_section = inspector_panel.column.find_widget_by_id("graphics_inspector_section") self.assertIsNotNone(graphics_section) - self.assertIn("Annular Ring", (i._graphic_type_model.value for i in graphics_section._handlers)) + self.assertIn("Annular Ring", (i._graphic_type_model.value for i in graphics_section._handler._graphic_handlers)) def test_wedge_graphic_inspector_updates_without_exception(self): with TestContext.create_memory_context() as test_context: @@ -1139,7 +1139,7 @@ def test_wedge_graphic_inspector_updates_without_exception(self): document_controller.periodic() graphics_section = inspector_panel.column.find_widget_by_id("graphics_inspector_section") self.assertIsNotNone(graphics_section) - self.assertIn("Wedge", (i._graphic_type_model.value for i in graphics_section._handlers)) + self.assertIn("Wedge", (i._graphic_type_model.value for i in graphics_section._handler._graphic_handlers)) def test_graphic_inspector_updates_for_when_data_shape_changes(self): # change from 2d item with a rectangle to a 1d item. what happens?