def __init__(self, *, completion_fn: typing.Optional[typing.Callable[ [], None]] = None): super().__init__(completion_fn=completion_fn) self.progress_value_model = Model.PropertyModel(0) self.message_str_model = Model.PropertyModel(str())
def __init__(self): self.state = Model.PropertyModel("idle") self.frame_count_model = Model.PropertyModel(20) self.progress_model = Model.PropertyModel(0) self.cancel_event = threading.Event() self.__grab_thread = None self.__record_thread = None
def __init__(self): self.cb1 = None self.cb2_current_index_model = Model.PropertyModel(1) self.cb2_current_index_model.on_value_changed = self.cb2_current_index_changed self.numbers = ["One", "Two", "Three"] self.numeros = Model.PropertyModel([]) self.numeros.value = ["Uno", "Dos", "Tres"]
def __init__(self, ui, statistics_model): super().__init__( ui.create_column_widget(properties={ "min-height": 18 * 3, "max-height": 18 * 3 })) # create property models for the UI self._stats1_property = Model.PropertyModel(str()) self._stats2_property = Model.PropertyModel(str()) self.__statistics_model = statistics_model def statistics_changed(key: str) -> None: if key == "value": statistics_data = self.__statistics_model.value statistic_strings = list() for key in sorted(statistics_data.keys()): value = statistics_data[key] if value is not None: statistic_str = "{0} {1}".format(key, value) else: statistic_str = "{0} {1}".format(key, _("N/A")) statistic_strings.append(statistic_str) self._stats1_property.value = "\n".join( statistic_strings[:(len(statistic_strings) + 1) // 2]) self._stats2_property.value = "\n".join( statistic_strings[(len(statistic_strings) + 1) // 2:]) self.__statistics_property_changed_event_listener = self.__statistics_model.property_changed_event.listen( statistics_changed) statistics_changed("value") stats_column1 = ui.create_column_widget(properties={ "min-width": 140, "max-width": 140 }) stats_column2 = ui.create_column_widget(properties={ "min-width": 140, "max-width": 140 }) stats_column1_label = ui.create_label_widget() stats_column2_label = ui.create_label_widget() stats_column1.add(stats_column1_label) stats_column2.add(stats_column2_label) stats_section = ui.create_row_widget() stats_section.add_spacing(13) stats_section.add(stats_column1) stats_section.add_stretch() stats_section.add(stats_column2) stats_section.add_spacing(13) stats_column1_label.bind_text( Binding.PropertyBinding(self._stats1_property, "value")) stats_column2_label.bind_text( Binding.PropertyBinding(self._stats2_property, "value")) self.content_widget.add(stats_section)
def __init__(self): self._event_loop = None # this will be injected by declarative UI engine # create a structured model by building a schema and then using the schema to create a structured model object. mode_title_field = StructuredModel.define_field( "title", StructuredModel.STRING) mode_balance_field = StructuredModel.define_field("balance", StructuredModel.INT, default=0) mode_schema = StructuredModel.define_record( "Mode", [mode_title_field, mode_balance_field]) mode_index_field = StructuredModel.define_field("mode_index", StructuredModel.INT, default=1) modes_field = StructuredModel.define_field( "modes", StructuredModel.define_array(mode_schema)) schema = StructuredModel.define_record("Configuration", [mode_index_field, modes_field]) # import pprint # print(pprint.pformat(schema)) self.model = StructuredModel.build_model(schema) # the title model is used for adding new modes. it is not part of the structured model. self.title_model = Model.PropertyModel() # the mode titles model is a property containing a list of mode titles. it is not part of the structured # model, but needs to be rebuilt when the list of modes in the model changes. add a listener for items # inserted/removed events and rebuild the mode titles model when those events are fired. self.mode_titles_model = Model.PropertyModel( [mode.title for mode in self.model.modes]) def modes_changed(k, v, i): if k == "modes": self.mode_titles_model.value = [ mode.title for mode in self.model.modes ] self.__modes_item_inserted_listener = self.model.item_inserted_event.listen( modes_changed) self.__modes_item_removed_listener = self.model.item_removed_event.listen( modes_changed) # add some initial modes self.model.modes.append( StructuredModel.build_model(mode_schema, value={"title": "One"})) self.model.modes.append( StructuredModel.build_model(mode_schema, value={"title": "Two"}))
def __init__(self): self.__probe_position_value = Model.PropertyModel() self.__probe_position_value.on_value_changed = self.set_probe_position self.__probe_state_stack = list() # parked, or scanning self.__probe_state_stack.append("parked") self.probe_state_changed_event = Event.Event() self.__subscan_state_value = Model.PropertyModel(SubscanState.INVALID) self.__subscan_region_value = Model.PropertyModel(None) self.scan_data_items_changed_event = Event.Event()
def connect_camera_hardware_source(self, camera_hardware_source): self.__exposure_time_ms_value_model = Model.PropertyModel() def update_exposure_time_ms(exposure_time_ms): if exposure_time_ms > 0: frame_parameters = camera_hardware_source.get_frame_parameters(0) frame_parameters.exposure_ms = exposure_time_ms camera_hardware_source.set_frame_parameters(0, frame_parameters) self.__update_estimate() self.__exposure_time_ms_value_model.on_value_changed = update_exposure_time_ms exposure_time_ms_value_binding = Binding.PropertyBinding(self.__exposure_time_ms_value_model, "value", converter=Converter.FloatToStringConverter("{0:.1f}")) def eels_profile_parameters_changed(profile_index, frame_parameters): if profile_index == 0: expected_dimensions = camera_hardware_source.get_expected_dimensions(frame_parameters.binning) self.__camera_width = expected_dimensions[1] self.__camera_height = expected_dimensions[0] self.__exposure_time_ms_value_model.value = frame_parameters.exposure_ms self.__update_estimate() self.__eels_frame_parameters_changed_event_listener = camera_hardware_source.frame_parameters_changed_event.listen(eels_profile_parameters_changed) eels_profile_parameters_changed(0, camera_hardware_source.get_frame_parameters(0)) self.__exposure_time_widget._widget.bind_text(exposure_time_ms_value_binding) # the widget will close the binding
class Handler(Declarative.Handler): radio_button_value = Model.PropertyModel(2) label_widget: typing.Optional[UserInterface.LabelWidget] = None def reset_clicked(self, widget: Declarative.UIWidget) -> None: self.radio_button_value.value = 2
def __init__( self, container: typing.Any, hardware_source: video_base.VideoHardwareSource ) -> None: self.container = container self.hardware_source = hardware_source self.settings = video_base.video_configuration.get_settings_model( hardware_source) self.settings_original = copy.deepcopy(self.settings) self.needs_saving_model = Model.PropertyModel(False) self.property_changed_event = Event.Event() # these will be assigned by declarative setup self.apply_button: typing.Optional[ UserInterface.PushButtonWidget] = None self.revert_button: typing.Optional[ UserInterface.PushButtonWidget] = None def settings_changed(property_name: str) -> None: self.needs_saving_model.value = True self.__settings_changed_event_listener = self.settings.property_changed_event.listen( settings_changed) if self.settings else None def needs_saving_model_changed( property_name: str) -> None: if self.apply_button: self.apply_button.enabled = self.needs_saving_model.value or False if self.revert_button: self.revert_button.enabled = self.needs_saving_model.value or False self.__needs_saving_changed_event_listener = self.needs_saving_model.property_changed_event.listen( needs_saving_model_changed)
def __init__(self, container, hardware_source): self.container = container self.hardware_source = hardware_source self.settings = video_base.video_configuration.get_settings_model( hardware_source) self.settings_original = copy.deepcopy(self.settings) self.needs_saving_model = Model.PropertyModel(False) self.property_changed_event = Event.Event() self.apply_button = None self.revert_button = None def settings_changed(property_name): self.needs_saving_model.value = True self.__settings_changed_event_listener = self.settings.property_changed_event.listen( settings_changed) def needs_saving_model_changed(property_name): if self.apply_button: self.apply_button.enabled = self.needs_saving_model.value if self.revert_button: self.revert_button.enabled = self.needs_saving_model.value self.__needs_saving_changed_event_listener = self.needs_saving_model.property_changed_event.listen( needs_saving_model_changed)
class Handler: tab_index_model = Model.PropertyModel(1) def switch3(self, widget): print("CLICKED 3") self.tab_index_model.value = 2
def __init__(self): self.sections = list() self.item_inserted_event = Event.Event() self.item_removed_event = Event.Event() self.sections.append(Section("Apples")) self.sections.append(Section("Oranges")) self.title_model = Model.PropertyModel()
class Handler: # method 1: explicitly handle events hello1_label = None def hello1_updated(self, widget, text): self.hello1_label.text = text if widget.focused: widget.select_all() # method 2: dialog handler becomes a model, explicit handling of hello2_text model property property_changed_event = Event.Event() __hello2_text = "Hello World Two" @property def hello2_text(self): return self.__hello2_text @hello2_text.setter def hello2_text(self, value): self.__hello2_text = value self.property_changed_event.fire("hello2_text") # method 3: use a property model hello3_model = Model.PropertyModel("Hello World Three")
def connect_scan_hardware_source(self, scan_hardware_source): self.__scan_width_model = Model.PropertyModel() self.__scan_height_model = Model.PropertyModel() scan_width_binding = Binding.PropertyBinding( self.__scan_width_model, "value", converter=Converter.IntegerToStringConverter()) scan_height_binding = Binding.PropertyBinding( self.__scan_height_model, "value", converter=Converter.IntegerToStringConverter()) def scan_profile_parameters_changed(profile_index, frame_parameters): if profile_index == 2: self.__scan_width_model.value = frame_parameters.size[1] self.__scan_height_model.value = frame_parameters.size[0] self.__scan_frame_parameters_changed_event_listener = scan_hardware_source.frame_parameters_changed_event.listen( scan_profile_parameters_changed) scan_profile_parameters_changed( 2, scan_hardware_source.get_frame_parameters(2)) def update_scan_width(scan_width): if scan_width > 0: frame_parameters = scan_hardware_source.get_frame_parameters(2) frame_parameters.size = frame_parameters.size[0], scan_width scan_hardware_source.set_frame_parameters(2, frame_parameters) self.__update_estimate() def update_scan_height(scan_height): if scan_height > 0: frame_parameters = scan_hardware_source.get_frame_parameters(2) frame_parameters.size = scan_height, frame_parameters.size[1] scan_hardware_source.set_frame_parameters(2, frame_parameters) self.__update_estimate() # only connect model to update hardware source after it has been initialized. self.__scan_width_model.on_value_changed = update_scan_width self.__scan_height_model.on_value_changed = update_scan_height self.__scan_width_widget._widget.bind_text( scan_width_binding) # the widget will close the binding self.__scan_height_widget._widget.bind_text( scan_height_binding) # the widget will close the binding
def __init__( self, ui_view: Declarative.UIDescription, video_sources: ListModel.ListModel[ video_base.VideoHardwareSource] ) -> None: self.ui_view = ui_view self.video_sources = video_sources self.video_source_type_index = Model.PropertyModel(0)
def __init__(self) -> None: super().__init__() self.cb1: typing.Optional[UserInterface.ComboBoxWidget] = None self.cb2_current_index_model = Model.PropertyModel(1) self.cb2_current_index_model.on_value_changed = self.cb2_current_index_changed self.numbers = ["One", "Two", "Three"] self.numeros = Model.PropertyModel[typing.List[str]]([]) self.numeros.value = ["Uno", "Dos", "Tres"]
def __init__(self, ui, app=None): super().__init__(ui, app) # a text model to hold the label widget text text_model = Model.PropertyModel(0) # make bitmap_data (random static) for icon push button bitmap = numpy.zeros((32, 32, 4), numpy.uint8) bitmap[..., 0] = (numpy.random.randn(32, 32) * 255).astype( numpy.uint8) # blue bitmap[..., 1] = (numpy.random.randn(32, 32) * 255).astype( numpy.uint8) # green bitmap[..., 2] = (numpy.random.randn(32, 32) * 255).astype( numpy.uint8) # red bitmap[..., 3] = 255 bitmap_data = bitmap.view(numpy.uint32).reshape(bitmap.shape[:-1]) # create the widgets for the window label_widget = self.ui.create_label_widget() push_button_widget = self.ui.create_push_button_widget("Push Me") icon_button_widget = self.ui.create_push_button_widget() icon_button_widget.icon = bitmap_data # create a row for the buttons button_row = self.ui.create_row_widget() button_row.add_spacing(13) button_row.add(push_button_widget) button_row.add_spacing(13) button_row.add(icon_button_widget) button_row.add_stretch() # create a row for the label label_row = self.ui.create_row_widget() label_row.add_spacing(13) label_row.add(label_widget) label_row.add_stretch() # create a column to hold the two rows and attach it to the window content = self.ui.create_column_widget() content.add(button_row) content.add(label_row) self.attach_widget(content) # when either button is clicked, this will be called def button_clicked(): text_model.value = text_model.value + 1 # connect the buttons to the button_clicked function push_button_widget.on_clicked = button_clicked icon_button_widget.on_clicked = button_clicked # and bind the label txt to the 'value' property of the text_model, but attach an integer-to-string converter to it. label_widget.bind_text( Binding.PropertyBinding( text_model, "value", converter=Converter.IntegerToStringConverter( format="You have clicked {:d} times.")))
def __init__(self, *, document_controller: DocumentController.DocumentController, **kwargs: typing.Any) -> None: self.radio_button_value: Model.PropertyModel[int] = Model.PropertyModel(0) u = Declarative.DeclarativeUI() top_row_items = list() bottom_row_items = list() modes = list() tool_actions = list() for action in Window.actions.values(): if action.action_id.startswith("window.set_tool_mode"): tool_actions.append(typing.cast(DocumentController.SetToolModeAction, action)) for i, tool_action in enumerate(tool_actions): tool_id = tool_action.tool_mode icon_png = tool_action.tool_icon tool_tip = tool_action.tool_tip key_shortcut = Window.action_shortcuts.get(tool_action.action_id, dict()).get("display_panel", None) if key_shortcut: tool_tip += f" ({key_shortcut})" modes.append(tool_id) assert icon_png is not None icon_data = CanvasItem.load_rgba_data_from_bytes(icon_png) icon_property = "icon_" + tool_id setattr(self, icon_property, icon_data) radio_button = u.create_radio_button(icon=f"@binding({icon_property})", value=i, group_value="@binding(radio_button_value.value)", width=32, height=24, tool_tip=tool_tip) if i % 2 == 0: top_row_items.append(radio_button) else: bottom_row_items.append(radio_button) top_row = u.create_row(*top_row_items) bottom_row = u.create_row(*bottom_row_items) self.ui_view = u.create_row(u.create_column(u.create_spacing(4), top_row, bottom_row, u.create_spacing(4), u.create_stretch())) self.radio_button_value.value = modes.index(document_controller.tool_mode) def tool_mode_changed(tool_mode: str) -> None: self.radio_button_value.value = modes.index(tool_mode) self.__tool_mode_changed_event_listener = document_controller.tool_mode_changed_event.listen(tool_mode_changed) tool_mode_changed(document_controller.tool_mode) def radio_button_changed(property: str) -> None: if property == "value": mode_index = self.radio_button_value.value if mode_index is not None: document_controller.tool_mode = modes[mode_index] self.__radio_button_value_listener = self.radio_button_value.property_changed_event.listen(radio_button_changed)
def __init__(self): # 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() def shape_index_changed(p: str = None) -> None: self.shape_page.value = self.shapes_model.items[ self.shape_index_model.value].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 __init__(self, settings): self.settings = settings self.camera_index_model = Model.PropertyModel() def camera_index_changed(index): formats = list(range(len(available_cameras))) self.settings.camera_index = formats[index] self.camera_index_model.on_value_changed = camera_index_changed self.camera_index_model.value = self.settings.camera_index
def __init__(self, settings): self.settings = settings self.camera_index_model = Model.PropertyModel() def camera_index_changed(index): formats = [None, 0, 1, 2, 3] self.settings.camera_index = formats[index] self.camera_index_model.on_value_changed = camera_index_changed self.camera_index_model.value = self.settings.camera_index + 1 if self.settings.camera_index is not None else 0
def __init__(self): # method 1: explicitly handle events self.hello1_label = None # method 2: dialog handler becomes a model, explicit handling of hello2_text model property self.property_changed_event = Event.Event() self.__hello2_text = "Hello World Two" # method 3: use a property model self.hello3_model = Model.PropertyModel("Hello World Three") # method 4: use a handler property directly, no update mechanism self.hello4_text = "Hello World Four"
def __init__(self) -> None: super().__init__() # method 1: explicitly handle events self.hello1_label: typing.Optional[UserInterface.LabelWidget] = None # method 2: dialog handler becomes a model, explicit handling of hello2_text model property self.property_changed_event = Event.Event() self.__hello2_text = "Hello World Two" # method 3: use a property model self.hello3_model = Model.PropertyModel("Hello World Three") # method 4: use a handler property directly, no update mechanism self.hello4_text = "Hello World Four"
def test_refcounts(self) -> None: with event_loop_context() as event_loop: # map stream, value stream stream = Stream.MapStream(Stream.ValueStream(0), lambda x: x) stream_ref = weakref.ref(stream) del stream self.assertIsNone(stream_ref()) # combine stream stream2 = Stream.CombineLatestStream[typing.Any, typing.Any]( [Stream.ValueStream(0), Stream.ValueStream(0)]) stream_ref2 = weakref.ref(stream2) del stream2 self.assertIsNone(stream_ref2()) # debounce stream3 = Stream.DebounceStream(Stream.ValueStream(0), 0.0, event_loop) stream_ref3 = weakref.ref(stream3) del stream3 self.assertIsNone(stream_ref3()) # sample stream4 = Stream.SampleStream(Stream.ValueStream(0), 0.0, event_loop) stream_ref4 = weakref.ref(stream4) del stream4 self.assertIsNone(stream_ref4()) # property changed event stream stream5 = Stream.PropertyChangedEventStream[typing.Any]( Model.PropertyModel(0), "value") stream_ref5 = weakref.ref(stream5) del stream5 self.assertIsNone(stream_ref5()) # optional stream stream6 = Stream.OptionalStream(Stream.ValueStream(0), lambda x: True) stream_ref6 = weakref.ref(stream6) del stream6 self.assertIsNone(stream_ref6()) # value stream action action = Stream.ValueStreamAction(Stream.ValueStream(0), lambda x: None) action_ref = weakref.ref(action) del action self.assertIsNone(action_ref()) # value change stream stream7 = Stream.ValueChangeStream(Stream.ValueStream(0)) stream_ref7 = weakref.ref(stream7) del stream7 self.assertIsNone(stream_ref7())
class Handler(Declarative.Handler): all_cb: typing.Optional[UserInterface.CheckBoxWidget] = None gain_cb: typing.Optional[UserInterface.CheckBoxWidget] = None dark_cb: typing.Optional[UserInterface.CheckBoxWidget] = None gain_enabled = True extra_model = Model.PropertyModel(True) def __init__(self) -> None: super().__init__() def extra_changed(value: typing.Optional[bool]) -> None: print(f"Extra {value}") self.extra_model.on_value_changed = extra_changed def checked(self, widget: Declarative.UIWidget, checked: bool) -> None: print(f"Checked: {checked}") self.__update_check_state() def check_state_changed(self, widget: Declarative.UIWidget, check_state: str) -> None: assert self.gain_cb assert self.dark_cb assert self.all_cb print(f"Check state: {check_state}") if check_state == "partial": check_state = "checked" if check_state != "partial": c = check_state == "checked" self.gain_cb.checked = c self.dark_cb.checked = c self.all_cb.checked = c self.extra_model.value = check_state == "checked" def __update_check_state(self) -> None: assert self.gain_cb assert self.dark_cb assert self.all_cb print(f"Compare {self.gain_cb.checked} to {self.dark_cb.checked}") if self.gain_cb.checked == self.dark_cb.checked: print(f"Setting {self.gain_cb.check_state}") self.all_cb.check_state = self.gain_cb.check_state else: print(f"Setting PARTIAL") self.all_cb.check_state = "partial"
class Handler: all_cb = None gain_cb = None dark_cb = None all_check_state = "partial" gain_enabled = True extra_model = Model.PropertyModel(True) def __init__(self): def extra_changed(value): print(f"Extra {value}") self.extra_model.on_value_changed = extra_changed def checked(self, widget, checked): print(f"Checked: {checked}") self.__update_check_state() def check_state_changed(self, widget, check_state): print(f"Check state: {check_state}") if check_state == "partial": check_state = "checked" if check_state != "partial": c = check_state == "checked" self.gain_cb.checked = c self.dark_cb.checked = c self.all_cb.checked = c self.extra_model.value = check_state == "checked" def __update_check_state(self): print(f"Compare {self.gain_cb.checked} to {self.dark_cb.checked}") if self.gain_cb.checked == self.dark_cb.checked: print(f"Setting {self.gain_cb.check_state}") self.all_cb.check_state = self.gain_cb.check_state else: print(f"Setting PARTIAL") self.all_cb.check_state = "partial"
def __init__(self, ui_view, video_sources): self.ui_view = ui_view self.video_sources = video_sources self.video_source_type_index = Model.PropertyModel(0)
def __init__(self) -> None: super().__init__() self.color_line_edit: typing.Optional[ UserInterface.LineEditWidget] = None self.model = Model.PropertyModel("red")
class Handler(Declarative.Handler): stack_index_model = Model.PropertyModel(1)
def __init__(self, document_controller: DocumentController.DocumentController, data_item: DataItem.DataItem) -> None: ui = document_controller.ui super().__init__(ui, _("Recorder"), parent_window=document_controller, persistent_id="Recorder" + str(data_item.uuid)) self.__recorder = Recorder(document_controller, data_item) self.ui = ui self.document_controller = document_controller self.__data_item = data_item self.__record_button = ui.create_push_button_widget(_("Record")) def thumbnail_widget_drag(mime_data: UserInterface.MimeData, thumbnail: typing.Optional[ DrawingContext.RGBA32Type], hot_spot_x: int, hot_spot_y: int) -> None: # use this convoluted base object for drag so that it doesn't disappear after the drag. self.content.drag(mime_data, thumbnail, hot_spot_x, hot_spot_y) display_item = document_controller.document_model.get_display_item_for_data_item( data_item) data_item_thumbnail_source = DataItemThumbnailWidget.DataItemThumbnailSource( ui, display_item=display_item) data_item_chooser_widget = DataItemThumbnailWidget.ThumbnailWidget( ui, data_item_thumbnail_source, Geometry.IntSize(48, 48)) data_item_chooser_widget.on_drag = thumbnail_widget_drag self.__recording_interval_property = Model.PropertyModel(1000) self.__recording_count_property = Model.PropertyModel(20) recording_period_widget = ui.create_line_edit_widget( properties={"width": 60}) recording_period_widget.bind_text( Binding.PropertyBinding( self.__recording_interval_property, "value", converter=Converter.IntegerToStringConverter())) recording_count_widget = ui.create_line_edit_widget( properties={"width": 60}) recording_count_widget.bind_text( Binding.PropertyBinding( self.__recording_count_property, "value", converter=Converter.IntegerToStringConverter())) row0 = ui.create_row_widget() row0.add_stretch() row0.add_spacing(8) row0.add(self.__record_button) row0.add_spacing(8) row1 = ui.create_row_widget() row1.add(ui.create_label_widget(_("Interval"))) row1.add_spacing(8) row1.add(recording_period_widget) row1.add_spacing(4) row1.add(ui.create_label_widget(_("msec"))) row1.add_spacing(8) row1.add_stretch() row2 = ui.create_row_widget() row2.add(ui.create_label_widget(_("Frames"))) row2.add_spacing(8) row2.add(recording_count_widget) row2.add_spacing(8) row2.add_stretch() column1 = ui.create_column_widget() column1.add(row1) column1.add_spacing(4) column1.add(row2) column1.add_spacing(4) column1.add(row0) button_row = ui.create_row_widget() button_row.add_spacing(8) button_row.add(data_item_chooser_widget) button_row.add_spacing(8) button_row.add_stretch() button_row.add_spacing(8) button_row.add(column1) button_row.add_spacing(8) def record_pressed() -> None: if self.__recorder.recording_state == "recording": self.__recorder.stop_recording() else: recording_interval = self.__recording_interval_property.value or 0.0 recording_count = self.__recording_count_property.value or 1 self.__recorder.start_recording(time.time(), recording_interval / 1000, recording_count) self.__record_button.on_clicked = record_pressed column = self.content column.add_spacing(6) column.add(button_row) column.add_spacing(6) def live_state_changed(is_live: bool) -> None: self.__record_button.enabled = is_live def recording_state_changed(recording_state: str) -> None: if recording_state == "recording": self.__record_button.text = _("Stop") else: self.__record_button.text = _("Record") def data_item_removed() -> None: self.request_close() self.__recorder.on_live_state_changed = live_state_changed self.__recorder.on_recording_state_changed = recording_state_changed self.__recorder.on_data_item_removed = data_item_removed live_state_changed(data_item.is_live) recording_state_changed("stopped")