From 253a76f2bc23e14bcaffc23dbe0576de119b925a Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Wed, 6 Mar 2024 14:07:06 +0100 Subject: [PATCH] feat(bevy_components): improved ui functionality * error handling * injection of invalid status & message in case the conversion did not work well * lots of minor improvements --- tools/bevy_components/components/operators.py | 56 +++++++-- tools/bevy_components/registry/operators.py | 2 +- tools/bevy_components/registry/ui.py | 107 ++++++++++-------- 3 files changed, 106 insertions(+), 59 deletions(-) diff --git a/tools/bevy_components/components/operators.py b/tools/bevy_components/components/operators.py index 1ac0086..9d308ef 100644 --- a/tools/bevy_components/components/operators.py +++ b/tools/bevy_components/components/operators.py @@ -165,6 +165,7 @@ class OT_rename_component(Operator): bl_label = "rename component" bl_options = {"UNDO"} + original_name: bpy.props.StringProperty(default="") # type: ignore new_name: StringProperty( name="new_name", description="new name of component", @@ -176,22 +177,59 @@ class OT_rename_component(Operator): registry = context.window_manager.components_registry type_infos = registry.type_infos settings = context.window_manager.bevy_component_rename_helper - original_name = settings.original_name + original_name = settings.original_name if self.original_name == "" else self.original_name new_name = self.new_name - print("renaming components: original name", settings.original_name, "new_name", self.new_name, "targets", self.target_objects) + print("FOO", self.original_name, "fsdf", settings.original_name) + + print("renaming components: original name", original_name, "new_name", self.new_name, "targets", self.target_objects) target_objects = json.loads(self.target_objects) - if original_name != '' and new_name != '' and len(target_objects) > 0: + errors = [] + if original_name != '' and new_name != '' and original_name != new_name and len(target_objects) > 0: for object_name in target_objects: object = bpy.data.objects[object_name] if object and original_name in object: - object[new_name] = object[original_name] - remove_component_from_object(object, original_name) - # attempt conversion - long_name = registry.short_names_to_long_names[new_name] - component_definition = type_infos[long_name] - add_component_to_object(object, component_definition, object[new_name]) + # get metadata + components_metadata = getattr(object, "components_meta", None) + component_meta = None + if components_metadata: + components_metadata = components_metadata.components + component_meta = next(filter(lambda component: component["name"] == new_name, components_metadata), None) + # copy data to new component, remove the old one + try: + object[new_name] = object[original_name] + remove_component_from_object(object, original_name) + except Exception as error: + if '__disable__update' in object: + del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure + if component_meta: + component_meta.invalid = True + component_meta.invalid_details = "unknow issue when renaming/transforming component, please remove it & add it back again" + + errors.append( "failed to copy old component value to new component: object: '" + object.name + "', error: " + str(error)) + + try: + # attempt conversion + long_name = registry.short_names_to_long_names[new_name] + component_definition = type_infos[long_name] + add_component_to_object(object, component_definition, object[new_name]) + except Exception as error: + if '__disable__update' in object: + del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure + if component_meta: + component_meta.invalid = True + component_meta.invalid_details = "wrong custom property value, overwrite them by changing the values in the ui or change them & regenerate ('Update UI from ...button')" + + errors.append( "wrong custom property values to generate target component: object: '" + object.name + "', error: " + str(error)) + + if len(errors) > 0: + self.report({'ERROR'}, "Failed to rename component: Errors:" + str(errors)) + else: + self.report({'INFO'}, "Sucessfully renamed component") + # TODO: clear data after we are done + self.original_name = "" + context.window_manager.bevy_component_rename_helper.original_name = "" return {'FINISHED'} diff --git a/tools/bevy_components/registry/operators.py b/tools/bevy_components/registry/operators.py index 10891d6..c2893d5 100644 --- a/tools/bevy_components/registry/operators.py +++ b/tools/bevy_components/registry/operators.py @@ -220,7 +220,7 @@ class OT_select_object(Operator): class OT_select_component_name_to_replace(Operator): """Select component name to replace""" bl_idname = "object.select_component_name_to_replace" - bl_label = "Select object" + bl_label = "Select component name for bulk replace" bl_options = {"UNDO"} component_name: StringProperty( diff --git a/tools/bevy_components/registry/ui.py b/tools/bevy_components/registry/ui.py index b17f061..f770d8b 100644 --- a/tools/bevy_components/registry/ui.py +++ b/tools/bevy_components/registry/ui.py @@ -61,6 +61,54 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): bl_options = {'DEFAULT_CLOSED'} bl_description = "advanced tooling" + + def draw_invalid_or_unregistered_header(self, layout, items): + row = layout.row() + + for item in items: + col = row.column() + col.label(text=item) + + + def draw_invalid_or_unregistered(self, layout, status, component_name, object): + available_components = bpy.context.window_manager.components_list + registry = bpy.context.window_manager.components_registry + registry_has_type_infos = registry.has_type_infos() + + row = layout.row() + + col = row.column() + col.label(text=component_name) + + col = row.column() + operator = col.operator(OT_select_object.bl_idname, text=object.name) + operator.object_name = object.name + + col = row.column() + col.label(text=status) + + col = row.column() + col.prop(available_components, "list", text="") + + col = row.column() + operator = col.operator(OT_rename_component.bl_idname, text="", icon="SHADERFX") #rename + new_name = registry.type_infos[available_components.list]['short_name'] if available_components.list in registry.type_infos else "" + operator.original_name = component_name + operator.target_objects = json.dumps([object.name]) + operator.new_name = new_name + col.enabled = registry_has_type_infos and component_name != "" and component_name != new_name + + + col = row.column() + operator = col.operator(RemoveComponentOperator.bl_idname, text="", icon="X") + operator.object_name = object.name + operator.component_name = component_name + + col = row.column() + col = row.column() + operator = col.operator(OT_select_component_name_to_replace.bl_idname, text="", icon="EYEDROPPER") #text="select for rename", + operator.component_name = component_name + def draw(self, context): layout = self.layout registry = bpy.context.window_manager.components_registry @@ -75,15 +123,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): objects_with_invalid_components = [] invalid_component_names = [] - row = layout.row() - col = row.column() - col.label(text="Status") - col = row.column() - col.label(text="Component") - col = row.column() - col.label(text="Object") - col = row.column() - col.label(text="-----") + self.draw_invalid_or_unregistered_header(layout, ["Component", "Object", "Status", "Target"]) for object in bpy.data.objects: # TODO: very inneficent if len(object.keys()) > 0: @@ -93,24 +133,8 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): for index, component_meta in enumerate(components_metadata): short_name = component_meta.name if component_meta.invalid: - row = layout.row() - col = row.column() - col.label(text="Invalid") - col = row.column() - col.label(text=short_name) - col = row.column() - operator = col.operator(OT_select_object.bl_idname, text=object.name) - operator.object_name = object.name - - col = row.column() - operator = col.operator(OT_select_component_name_to_replace.bl_idname, text="select for rename") - operator.component_name = short_name - - col = row.column() - operator = row.operator(RemoveComponentOperator.bl_idname, text="", icon="X") - operator.object_name = object.name - operator.component_name = short_name - + self.draw_invalid_or_unregistered(layout, "Invalid", short_name, object) + if not object.name in objects_with_invalid_components: objects_with_invalid_components.append(object.name) @@ -122,23 +146,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): for custom_property in object.keys(): if custom_property != 'components_meta' and custom_property not in comp_names: - row = layout.row() - col = row.column() - col.label(text="Unregistered") - col = row.column() - col.label(text=custom_property) - col = row.column() - operator = col.operator(OT_select_object.bl_idname, text=object.name) - operator.object_name = object.name - - col = row.column() - operator = col.operator(OT_select_component_name_to_replace.bl_idname, text="select for rename") - operator.component_name = custom_property - - col = row.column() - operator = row.operator(RemoveComponentOperator.bl_idname, text="", icon="X") - operator.object_name = object.name - operator.component_name = custom_property + self.draw_invalid_or_unregistered(layout, "Unregistered", custom_property, object) if not object.name in objects_with_invalid_components: objects_with_invalid_components.append(object.name) @@ -146,6 +154,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): invalid_component_names.append(custom_property) layout.separator() layout.separator() + original_name = bpy.context.window_manager.bevy_component_rename_helper.original_name row = layout.row() col = row.column() @@ -158,23 +167,23 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): row = layout.row() col = row.column() box = col.box() - box.label(text=bpy.context.window_manager.bevy_component_rename_helper.original_name) + box.label(text=original_name) col = row.column() col.prop(available_components, "list", text="") #row.prop(available_components, "filter",text="Filter") - + col = row.column() - operator = col.operator(OT_rename_component.bl_idname, text="rename") + operator = col.operator(OT_rename_component.bl_idname, text="apply", icon="SHADERFX") operator.target_objects = json.dumps(objects_with_invalid_components) new_name = registry.type_infos[available_components.list]['short_name'] if available_components.list in registry.type_infos else "" operator.new_name = new_name - col.enabled = registry_has_type_infos + col.enabled = registry_has_type_infos and original_name != "" and original_name != new_name col = row.column() operator = row.operator(RemoveComponentFromAllObjectsOperator.bl_idname, text="", icon="X") operator.component_name = context.window_manager.bevy_component_rename_helper.original_name - col.enabled = registry_has_type_infos + col.enabled = registry_has_type_infos and original_name != "" layout.separator() layout.separator()