From ba4e2c03e6221c38c5151ebdb8db9ca5011174e4 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Wed, 12 Jun 2024 19:33:12 +0200 Subject: [PATCH] feat(Blenvy): fixed/ updated rename/fixing tools * now works correctly for both single, bulk, on objects & collections * related fixes , tweaks & UI improvements --- tools/blenvy/TODO.md | 16 +- tools/blenvy/__init__.py | 9 +- .../bevy_components/components/metadata.py | 18 +- .../bevy_components/components/operators.py | 175 ++++++++++++++++-- .../add_ons/bevy_components/components/ui.py | 88 +++++---- .../bevy_components/registry/operators.py | 139 +------------- tools/blenvy/add_ons/bevy_components/utils.py | 52 ++++-- tools/blenvy/blueprints/operators.py | 6 - 8 files changed, 282 insertions(+), 221 deletions(-) diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index a76b5ca..a10edf4 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -51,11 +51,11 @@ Blueprints: Components: - [x] add support for adding components to collections - - [ ] upgrade all operators: + - [x] upgrade all operators: - [x] add - [x] remove - [x] copy & paste - - [ ] BLENVY_OT_component_rename_component + - [x] BLENVY_OT_component_rename_component - [x] BLENVY_OT_component_fix - [ ] add handling for core::ops::Range & other ranges - [x] fix is_component_valid that is used in gltf_auto_export @@ -64,21 +64,23 @@ Components: - [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set - [ ] handle missing types in registry for keys & values - - [ ] Add correct upgrade handling from individual component to bevy_components + - [x] Add correct upgrade handling from individual component to bevy_components - [x] Settings handling: - [x] move saveable settings out to a settings file - [x] update save & load - [x] add handling of polling frequency & enabling - [x] move advanced tools to components tab - - [ ] remove most of the (bulk) advanced tools, too complex, too unclear (even for me !) and of limited use + - [x] remove most of the (bulk) advanced tools, too complex, too unclear (even for me !) and of limited use - component renaming should be kept, but perhaps simplified: - if a renaming fails because the parameters are incompatible, nuke the old parameters - perhaps just add a display list of all NON component custom properties, so the user can find them easilly ? - - [ ] status "unregistered" is often false and misleading + - [x] status "unregistered" is often false and misleading -> see in registry ui "for custom_property in object.keys():" + - [x] overhaul / improve the component selector (with built in searching, etc) - [x] remove select_component_name_to_replace + - [ ] display of invalid components is not working ? General things to solve: @@ -148,7 +150,7 @@ General issues: -- [ ] overall cleanup - - [ ] object.add_bevy_component => blenvy.component_add +- [x] overall cleanup + - [x] object.add_bevy_component => blenvy.component_add clear && pytest -svv --blender-template ../../testing/bevy_example/art/testing_library.blend --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration_prepare.py && pytest -svv --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration.py \ No newline at end of file diff --git a/tools/blenvy/__init__.py b/tools/blenvy/__init__.py index e8e38b9..02289a8 100644 --- a/tools/blenvy/__init__.py +++ b/tools/blenvy/__init__.py @@ -17,16 +17,16 @@ from bpy.props import (StringProperty) # components management -from .add_ons.bevy_components.components.operators import BLENVY_OT_component_copy, BLENVY_OT_component_fix, BLENVY_OT_component_rename_component, BLENVY_OT_component_remove_from_all_items, BLENVY_OT_component_remove, BLENVY_OT_component_from_custom_property, BLENVY_OT_component_paste, BLENVY_OT_component_add, RenameHelper, BLENVY_OT_component_toggle_visibility +from .add_ons.bevy_components.components.operators import BLENVY_OT_component_copy, BLENVY_OT_component_fix, BLENVY_OT_component_rename_component, BLENVY_OT_component_remove_from_all_items, BLENVY_OT_component_remove, BLENVY_OT_component_from_custom_property, BLENVY_OT_component_paste, BLENVY_OT_component_add, RenameHelper, BLENVY_OT_component_toggle_visibility, BLENVY_OT_components_refresh_custom_properties_all, BLENVY_OT_components_refresh_custom_properties_current, BLENVY_OT_components_refresh_propgroups_all, BLENVY_OT_components_refresh_propgroups_current from .add_ons.bevy_components.registry.registry import ComponentsRegistry,MissingBevyType -from .add_ons.bevy_components.registry.operators import (BLENVY_OT_components_refresh_custom_properties_all, BLENVY_OT_components_refresh_custom_properties_current, BLENVY_OT_components_refresh_propgroups_all, BLENVY_OT_components_refresh_propgroups_current, BLENVY_OT_components_registry_reload, BLENVY_OT_components_registry_browse_schema) +from .add_ons.bevy_components.registry.operators import (BLENVY_OT_components_registry_reload, BLENVY_OT_components_registry_browse_schema) from .add_ons.bevy_components.registry.ui import (BLENVY_PT_components_missing_types_panel, BLENVY_UL_components_missing_types) from .add_ons.bevy_components.components.metadata import (ComponentMetadata, ComponentsMeta) from .add_ons.bevy_components.components.lists import BLENVY_OT_component_list_actions, BLENVY_OT_component_list_add_item, BLENVY_OT_component_list_remove_item, BLENVY_OT_component_list_select_item from .add_ons.bevy_components.components.maps import BLENVY_OT_component_map_actions from .add_ons.bevy_components.components.ui import BLENVY_PT_components_panel, BLENVY_PT_component_tools_panel from .add_ons.bevy_components.settings import ComponentsSettings -from .add_ons.bevy_components.utils import BLENVY_OT_object_select +from .add_ons.bevy_components.utils import BLENVY_OT_item_select # auto export from .add_ons.auto_export import gltf_post_export_callback @@ -90,11 +90,10 @@ classes = [ BLENVY_OT_components_registry_reload, BLENVY_OT_components_refresh_custom_properties_all, BLENVY_OT_components_refresh_custom_properties_current, - BLENVY_OT_components_refresh_propgroups_all, BLENVY_OT_components_refresh_propgroups_current, - BLENVY_OT_object_select, + BLENVY_OT_item_select, BLENVY_PT_components_panel, BLENVY_PT_component_tools_panel, diff --git a/tools/blenvy/add_ons/bevy_components/components/metadata.py b/tools/blenvy/add_ons/bevy_components/components/metadata.py index 8ee1757..038f31c 100644 --- a/tools/blenvy/add_ons/bevy_components/components/metadata.py +++ b/tools/blenvy/add_ons/bevy_components/components/metadata.py @@ -168,6 +168,7 @@ def add_metadata_to_components_without_metadata(item): # adds a component to an item (including metadata) using the provided component definition & optional value def add_component_to_item(item, component_definition, value=None): + warnings = [] cleanup_invalid_metadata(item) if item is not None: # print("add_component_to_item", component_definition) @@ -182,10 +183,15 @@ def add_component_to_item(item, component_definition, value=None): value = property_group_value_to_custom_property_value(propertyGroup, definition, registry, None) else: # we have provided a value, that is a raw , custom property value, to set the value of the propertyGroup item["__disable__update"] = True # disable update callback while we set the values of the propertyGroup "tree" (as a propertyGroup can contain other propertyGroups) - property_group_value_from_custom_property_value(propertyGroup, definition, registry, value) + try: + property_group_value_from_custom_property_value(propertyGroup, definition, registry, value) + except: + # if we failed to get the value, we default... to the default + value = property_group_value_to_custom_property_value(propertyGroup, definition, registry, None) + warnings.append(f"failed to get the initial value of {item.name}, using default value") del item["__disable__update"] - upsert_bevy_component(item, long_name, value) + return warnings def upsert_component_in_item(item, long_name, registry): # print("upsert_component_in_item", item, "component name", component_name) @@ -338,17 +344,17 @@ def add_component_from_custom_property(item): add_metadata_to_components_without_metadata(item) apply_customProperty_values_to_item_propertyGroups(item) -def rename_component(item, original_long_name, new_long_name): - registry = bpy.context.window_manager.components_registry +def rename_component(registry, item, original_long_name, new_long_name): type_infos = registry.type_infos component_definition = type_infos[new_long_name] component_ron_value = get_bevy_component_value_by_long_name(item=item, long_name=original_long_name) if component_ron_value is None and original_long_name in item: component_ron_value = item[original_long_name] - + remove_component_from_item(item, original_long_name) - add_component_to_item(item, component_definition, component_ron_value) + print("remove & rename") + return add_component_to_item(item, component_definition, component_ron_value) def toggle_component(item, component_name): diff --git a/tools/blenvy/add_ons/bevy_components/components/operators.py b/tools/blenvy/add_ons/bevy_components/components/operators.py index 134206a..d0fb25e 100644 --- a/tools/blenvy/add_ons/bevy_components/components/operators.py +++ b/tools/blenvy/add_ons/bevy_components/components/operators.py @@ -4,7 +4,8 @@ import bpy from bpy_types import Operator from bpy.props import (StringProperty) -from .metadata import add_component_from_custom_property, add_component_to_item, apply_propertyGroup_values_to_item_customProperties_for_component, copy_propertyGroup_values_to_another_item, get_bevy_component_value_by_long_name, get_bevy_components, is_bevy_component_in_item, remove_component_from_item, rename_component, toggle_component +from .metadata import add_component_from_custom_property, add_component_to_item, apply_customProperty_values_to_item_propertyGroups, apply_propertyGroup_values_to_item_customProperties, apply_propertyGroup_values_to_item_customProperties_for_component, copy_propertyGroup_values_to_another_item, get_bevy_component_value_by_long_name, get_bevy_components, is_bevy_component_in_item, remove_component_from_item, rename_component, toggle_component + from ..utils import get_selected_object_or_collection class BLENVY_OT_component_add(Operator): @@ -226,7 +227,7 @@ class BLENVY_OT_component_rename_component(Operator): @classmethod def register(cls): - bpy.types.WindowManager.components_rename_progress = bpy.props.FloatProperty(default=-1.0) #bpy.props.PointerProperty(type=RenameHelper) + bpy.types.WindowManager.components_rename_progress = bpy.props.FloatProperty(default=-1.0) @classmethod def unregister(cls): @@ -234,7 +235,6 @@ class BLENVY_OT_component_rename_component(Operator): def execute(self, context): registry = context.window_manager.components_registry - type_infos = registry.type_infos settings = context.window_manager.bevy_component_rename_helper original_name = settings.original_name if self.original_name == "" else self.original_name target_name = self.target_name @@ -243,19 +243,29 @@ class BLENVY_OT_component_rename_component(Operator): print("renaming components: original name", original_name, "target_name", self.target_name, "targets", self.target_items) target_items = json.loads(self.target_items) errors = [] + warnings = [] total = len(target_items) + if original_name != '' and target_name != '' and original_name != target_name and len(target_items) > 0: - for index, item_name in enumerate(target_items): - object = bpy.data.objects[item_name] - if object and original_name in get_bevy_components(object) or original_name in object: + for index, item_data in enumerate(target_items): + [item_name, item_type] = item_data + item = None + if item_type == "OBJECT": + item = bpy.data.objects[item_name] + elif item_type == "COLLECTION": + item = bpy.data.collections[item_name] + + print("heloooo", item, get_bevy_components(item)) + + if item and original_name in get_bevy_components(item) or original_name in item: try: # attempt conversion - rename_component(item=object, original_long_name=original_name, new_long_name=target_name) + warnings += rename_component(registry=registry, item=item, original_long_name=original_name, new_long_name=target_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 - components_metadata = getattr(object, "components_meta", None) + if '__disable__update' in item: + del item["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure + components_metadata = getattr(item, "components_meta", None) if components_metadata: components_metadata = components_metadata.components component_meta = next(filter(lambda component: component["long_name"] == target_name, components_metadata), None) @@ -263,8 +273,8 @@ class BLENVY_OT_component_rename_component(Operator): 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" - errors.append( "wrong custom property values to generate target component: object: '" + object.name + "', error: " + str(error)) - + errors.append( "wrong custom property values to generate target component: object: '" + item.name + "', error: " + str(error)) + progress = index / total context.window_manager.components_rename_progress = progress @@ -276,7 +286,7 @@ class BLENVY_OT_component_rename_component(Operator): if len(errors) > 0: self.report({'ERROR'}, "Failed to rename component: Errors:" + str(errors)) else: - self.report({'INFO'}, "Sucessfully renamed component") + self.report({'INFO'}, f"Sucessfully renamed component for {total} items: Warnings: {str(warnings)}") #clear data after we are done self.original_name = "" @@ -353,3 +363,142 @@ class BLENVY_OT_component_toggle_visibility(Operator): toggle_component(target, self.component_name) return {'FINISHED'} + + + + +class BLENVY_OT_components_refresh_custom_properties_all(Operator): + """Apply registry to ALL objects: update the custom property values of all objects based on their definition, if any""" + bl_idname = "object.refresh_custom_properties_all" + bl_label = "Apply Registry to all objects" + bl_options = {"UNDO"} + + @classmethod + def register(cls): + bpy.types.WindowManager.custom_properties_from_components_progress_all = bpy.props.FloatProperty(default=-1.0) + + @classmethod + def unregister(cls): + del bpy.types.WindowManager.custom_properties_from_components_progress_all + + def execute(self, context): + print("apply registry to all") + #context.window_manager.components_registry.load_schema() + total = len(bpy.data.objects) + + for index, object in enumerate(bpy.data.objects): + apply_propertyGroup_values_to_item_customProperties(object) + progress = index / total + context.window_manager.custom_properties_from_components_progress_all = progress + # now force refresh the ui + bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) + context.window_manager.custom_properties_from_components_progress_all = -1.0 + + return {'FINISHED'} + +class BLENVY_OT_components_refresh_custom_properties_current(Operator): + """Apply registry to CURRENT object: update the custom property values of current object based on their definition, if any""" + bl_idname = "object.refresh_custom_properties_current" + bl_label = "Apply Registry to current object" + bl_options = {"UNDO"} + + @classmethod + def register(cls): + bpy.types.WindowManager.custom_properties_from_components_progress = bpy.props.FloatProperty(default=-1.0) + + @classmethod + def unregister(cls): + del bpy.types.WindowManager.custom_properties_from_components_progress + + def execute(self, context): + print("apply registry to current object") + object = context.object + context.window_manager.custom_properties_from_components_progress = 0.5 + # now force refresh the ui + bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) + apply_propertyGroup_values_to_item_customProperties(object) + + context.window_manager.custom_properties_from_components_progress = -1.0 + return {'FINISHED'} + + +class BLENVY_OT_components_refresh_propgroups_current(Operator): + """Update UI values from custom properties to CURRENT object""" + bl_idname = "object.refresh_ui_from_custom_properties_current" + bl_label = "Apply custom_properties to current object" + bl_options = {"UNDO"} + + @classmethod + def register(cls): + bpy.types.WindowManager.components_from_custom_properties_progress = bpy.props.FloatProperty(default=-1.0) + + @classmethod + def unregister(cls): + del bpy.types.WindowManager.components_from_custom_properties_progress + + def execute(self, context): + print("apply custom properties to current object") + object = context.object + error = False + try: + apply_customProperty_values_to_item_propertyGroups(object) + progress = 0.5 + context.window_manager.components_from_custom_properties_progress = progress + try: + # now force refresh the ui + bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) + except:pass # ony run in ui + + except Exception as error_message: + del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure + error = True + self.report({'ERROR'}, "Failed to update propertyGroup values from custom property: Error:" + str(error_message)) + if not error: + self.report({'INFO'}, "Sucessfully generated UI values for custom properties for selected object") + context.window_manager.components_from_custom_properties_progress = -1.0 + + return {'FINISHED'} + + +class BLENVY_OT_components_refresh_propgroups_all(Operator): + """Update UI values from custom properties to ALL object""" + bl_idname = "object.refresh_ui_from_custom_properties_all" + bl_label = "Apply custom_properties to all objects" + bl_options = {"UNDO"} + + @classmethod + def register(cls): + bpy.types.WindowManager.components_from_custom_properties_progress_all = bpy.props.FloatProperty(default=-1.0) + + @classmethod + def unregister(cls): + del bpy.types.WindowManager.components_from_custom_properties_progress_all + + def execute(self, context): + print("apply custom properties to all object") + bpy.context.window_manager.components_registry.disable_all_object_updates = True + errors = [] + total = len(bpy.data.objects) + + for index, object in enumerate(bpy.data.objects): + + try: + apply_customProperty_values_to_item_propertyGroups(object) + except Exception as error: + del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure + errors.append( "object: '" + object.name + "', error: " + str(error)) + + progress = index / total + context.window_manager.components_from_custom_properties_progress_all = progress + # now force refresh the ui + bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) + + + + if len(errors) > 0: + self.report({'ERROR'}, "Failed to update propertyGroup values from custom property: Errors:" + str(errors)) + else: + self.report({'INFO'}, "Sucessfully generated UI values for custom properties for all objects") + bpy.context.window_manager.components_registry.disable_all_object_updates = False + context.window_manager.components_from_custom_properties_progress_all = -1.0 + return {'FINISHED'} diff --git a/tools/blenvy/add_ons/bevy_components/components/ui.py b/tools/blenvy/add_ons/bevy_components/components/ui.py index 56a7afc..50bd33e 100644 --- a/tools/blenvy/add_ons/bevy_components/components/ui.py +++ b/tools/blenvy/add_ons/bevy_components/components/ui.py @@ -3,9 +3,6 @@ import bpy from ..utils import get_selection_type from .metadata import do_item_custom_properties_have_missing_metadata, get_bevy_components -from .operators import BLENVY_OT_component_add, BLENVY_OT_component_copy, BLENVY_OT_component_fix, BLENVY_OT_component_remove, BLENVY_OT_component_paste, BLENVY_OT_component_toggle_visibility - -from ..utils import get_selection_type def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None): @@ -201,7 +198,7 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component # add components row = layout.row(align=True) - op = row.operator(BLENVY_OT_component_add.bl_idname, text="Add", icon="ADD") + op = row.operator("blenvy.component_add", text="Add", icon="ADD") op.component_type = selected_component row.enabled = selected_component != '' @@ -209,7 +206,7 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component # paste components row = layout.row(align=True) - row.operator(BLENVY_OT_component_paste.bl_idname, text="Paste component ("+bpy.context.window_manager.copied_source_component_name+")", icon="PASTEDOWN") + row.operator("blenvy.component_paste", text="Paste component ("+bpy.context.window_manager.copied_source_component_name+")", icon="PASTEDOWN") row.enabled = registry_has_type_infos and context.window_manager.copied_source_item_name != '' layout.separator() @@ -226,7 +223,6 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component #print("components_names", dict(components_bla).keys()) for component_name in sorted(get_bevy_components(object_or_collection)) : # sorted by component name, practical - #print("component_name", component_name) if component_name == "components_meta": continue # anything withouth metadata gets skipped, we only want to see real components, not all custom props @@ -279,17 +275,17 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component if propertyGroup: unit_struct = len(propertyGroup.field_names) == 0 if unit_struct: - op = row.operator(BLENVY_OT_component_fix.bl_idname, text="", icon="SHADERFX") + op = row.operator("blenvy.component_fix", text="", icon="SHADERFX") op.component_name = component_name row.separator() - op = row.operator(BLENVY_OT_component_remove.bl_idname, text="", icon="X") + op = row.operator("blenvy.component_remove", text="", icon="X") op.component_name = component_name op.item_name = object_or_collection.name op.item_type = get_selection_type(object_or_collection) row.separator() - op = row.operator(BLENVY_OT_component_copy.bl_idname, text="", icon="COPYDOWN") + op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN") op.source_component_name = component_name op.source_item_name = object_or_collection.name op.source_item_type = get_selection_type(object_or_collection) @@ -297,13 +293,12 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component #if not single_field: toggle_icon = "TRIA_DOWN" if component_visible else "TRIA_RIGHT" - op = row.operator(BLENVY_OT_component_toggle_visibility.bl_idname, text="", icon=toggle_icon) + op = row.operator("blenvy.component_toggle_visibility", text="", icon=toggle_icon) op.component_name = component_name #row.separator() - class BLENVY_PT_component_tools_panel(bpy.types.Panel): """panel listing all the missing bevy types in the schema""" bl_idname = "BLENVY_PT_component_tools_panel" @@ -327,7 +322,8 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): col = row.column() col.label(text=item) - def draw_invalid_or_unregistered(self, layout, status, component_name, target): + def draw_invalid_or_unregistered(self, layout, status, component_name, target, item_type): + item_type_short = item_type.lower() registry = bpy.context.window_manager.components_registry registry_has_type_infos = registry.has_type_infos() selected_component = target.components_meta.component_selector @@ -335,8 +331,9 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): row = layout.row() col = row.column() - operator = col.operator("object.select", text=target.name) + operator = col.operator("blenvy.select_item", text=f"{target.name}({item_type_short})") operator.target_name = target.name + operator.item_type = item_type col = row.column() col.label(text=status) @@ -352,11 +349,11 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): col = row.column() operator = col.operator("blenvy.component_rename", text="", icon="SHADERFX") #rename - target_name = registry.type_infos[selected_component]['long_name'] if selected_component in registry.type_infos else "" + target_component_name = registry.type_infos[selected_component]['long_name'] if selected_component in registry.type_infos else "" operator.original_name = component_name - operator.target_items = json.dumps([target.name]) - operator.target_name = target_name - col.enabled = registry_has_type_infos and component_name != "" and component_name != target_name + operator.target_items = json.dumps([(target.name, item_type)]) # tupple + operator.target_name = target_component_name + col.enabled = registry_has_type_infos and component_name != "" and target_component_name != "" and component_name != target_component_name col = row.column() @@ -365,17 +362,18 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): operator.component_name = component_name operator.item_type = get_selection_type(target) - def draw_invalid_item_entry(self, layout, item, invalid_component_names, items_with_invalid_components): + def draw_invalid_item_entry(self, layout, item, invalid_component_names, items_with_invalid_components, item_type): + blenvy_custom_properties = ['components_meta', 'bevy_components', 'user_assets', 'generated_assets' ] # some of our own hard coded custom properties that should be ignored if "components_meta" in item: components_metadata = item.components_meta.components object_component_names = [] for index, component_meta in enumerate(components_metadata): long_name = component_meta.long_name if component_meta.invalid: - self.draw_invalid_or_unregistered(layout, "Invalid", long_name, item) + self.draw_invalid_or_unregistered(layout, "Invalid", long_name, item, item_type) if not item.name in items_with_invalid_components: - items_with_invalid_components.append(item.name) + items_with_invalid_components.append((item.name, item_type)) if not long_name in invalid_component_names: invalid_component_names.append(long_name) @@ -389,14 +387,14 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): # Upgrade Needed (Old-style component) status = None - if custom_property != 'components_meta' and custom_property != 'bevy_components' and custom_property not in object_component_names: + if custom_property not in blenvy_custom_properties and custom_property not in object_component_names: status = "Upgrade Needed" if status is not None: - self.draw_invalid_or_unregistered(layout, status, custom_property, item) + self.draw_invalid_or_unregistered(layout, status, custom_property, item, item_type) if not item.name in items_with_invalid_components: - items_with_invalid_components.append(item.name) + items_with_invalid_components.append((item.name, item_type)) """if not long_name in invalid_component_names: invalid_component_names.append(custom_property)""" # FIXME @@ -408,29 +406,50 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): selected_component = bpy.context.window_manager.blenvy.components.component_selector row = layout.row() - box= row.box() - box.label(text="Invalid/ unregistered components") + row.label(text= "------------------ Single item actions: Rename / Fix / Upgrade -------------------")#"Invalid/ unregistered components") items_with_invalid_components = [] invalid_component_names = [] + items_with_original_components = [] + self.draw_invalid_or_unregistered_header(layout, ["Item","Status", "Component", "Target"]) + # for possible bulk actions + original_name = bpy.context.window_manager.blenvy.components.source_component_selector + target_component_name = bpy.context.window_manager.blenvy.components.target_component_selector + for object in bpy.data.objects: # TODO: very inneficent if len(object.keys()) > 0: - self.draw_invalid_item_entry(layout, object, invalid_component_names, items_with_invalid_components) + self.draw_invalid_item_entry(layout, object, invalid_component_names, items_with_invalid_components, "OBJECT") + + if original_name != "" and "components_meta" in object: + components_metadata = object.components_meta.components + for index, component_meta in enumerate(components_metadata): + long_name = component_meta.long_name + if long_name == original_name: + items_with_original_components.append((object.name, "OBJECT")) for collection in bpy.data.collections: if len(collection.keys()) > 0: - self.draw_invalid_item_entry(layout, collection, invalid_component_names, items_with_invalid_components) + self.draw_invalid_item_entry(layout, collection, invalid_component_names, items_with_invalid_components, "COLLECTION") + if original_name != "" and "components_meta" in collection: + components_metadata = collection.components_meta.components + for index, component_meta in enumerate(components_metadata): + long_name = component_meta.long_name + if long_name == original_name: + items_with_original_components.append((collection.name, "COLLECTION")) + if len(items_with_invalid_components) == 0: + layout.label(text="Nothing to see here , all good !") + + #print("items_with_original_components", items_with_original_components) layout.separator() layout.separator() - layout.label(text="------------------Bulk actions: Rename/ Upgrade -------------------") - original_name = bpy.context.window_manager.blenvy.components.source_component_selector - target_name = bpy.context.window_manager.blenvy.components.target_component_selector - + row = layout.row() + row.label(text="------------------Bulk actions: Rename / Fix / Upgrade -------------------") + row = layout.row() col = row.column() col.label(text="Component") @@ -450,9 +469,10 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel): components_rename_progress = context.window_manager.components_rename_progress if components_rename_progress == -1.0: operator = col.operator("blenvy.component_rename", text="apply", icon="SHADERFX") - operator.target_items = json.dumps(items_with_invalid_components) - operator.target_name = target_name - col.enabled = registry_has_type_infos and original_name != "" and original_name != target_name + operator.original_name = original_name + operator.target_name = target_component_name + operator.target_items = json.dumps(items_with_original_components) + col.enabled = registry_has_type_infos and original_name != "" and original_name != target_component_name else: if hasattr(layout,"progress") : # only for Blender > 4.0 col.progress(factor = components_rename_progress, text=f"updating {components_rename_progress * 100.0:.2f}%") diff --git a/tools/blenvy/add_ons/bevy_components/registry/operators.py b/tools/blenvy/add_ons/bevy_components/registry/operators.py index 2d91347..dc71961 100644 --- a/tools/blenvy/add_ons/bevy_components/registry/operators.py +++ b/tools/blenvy/add_ons/bevy_components/registry/operators.py @@ -5,8 +5,7 @@ from bpy.props import (StringProperty) from bpy_extras.io_utils import ImportHelper from blenvy.settings import upsert_settings - -from ..components.metadata import apply_customProperty_values_to_item_propertyGroups, apply_propertyGroup_values_to_item_customProperties, ensure_metadata_for_all_items +from ..components.metadata import ensure_metadata_for_all_items from ..propGroups.prop_groups import generate_propertyGroups_for_components class BLENVY_OT_components_registry_reload(Operator): @@ -36,142 +35,6 @@ class BLENVY_OT_components_registry_reload(Operator): region.tag_redraw() return {'FINISHED'} - -class BLENVY_OT_components_refresh_custom_properties_all(Operator): - """Apply registry to ALL objects: update the custom property values of all objects based on their definition, if any""" - bl_idname = "object.refresh_custom_properties_all" - bl_label = "Apply Registry to all objects" - bl_options = {"UNDO"} - - @classmethod - def register(cls): - bpy.types.WindowManager.custom_properties_from_components_progress_all = bpy.props.FloatProperty(default=-1.0) #bpy.props.PointerProperty(type=RenameHelper) - - @classmethod - def unregister(cls): - del bpy.types.WindowManager.custom_properties_from_components_progress_all - - def execute(self, context): - print("apply registry to all") - #context.window_manager.components_registry.load_schema() - total = len(bpy.data.objects) - - for index, object in enumerate(bpy.data.objects): - apply_propertyGroup_values_to_item_customProperties(object) - progress = index / total - context.window_manager.custom_properties_from_components_progress_all = progress - # now force refresh the ui - bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) - context.window_manager.custom_properties_from_components_progress_all = -1.0 - - return {'FINISHED'} - -class BLENVY_OT_components_refresh_custom_properties_current(Operator): - """Apply registry to CURRENT object: update the custom property values of current object based on their definition, if any""" - bl_idname = "object.refresh_custom_properties_current" - bl_label = "Apply Registry to current object" - bl_options = {"UNDO"} - - @classmethod - def register(cls): - bpy.types.WindowManager.custom_properties_from_components_progress = bpy.props.FloatProperty(default=-1.0) #bpy.props.PointerProperty(type=RenameHelper) - - @classmethod - def unregister(cls): - del bpy.types.WindowManager.custom_properties_from_components_progress - - def execute(self, context): - print("apply registry to current object") - object = context.object - context.window_manager.custom_properties_from_components_progress = 0.5 - # now force refresh the ui - bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) - apply_propertyGroup_values_to_item_customProperties(object) - - context.window_manager.custom_properties_from_components_progress = -1.0 - return {'FINISHED'} - - -class BLENVY_OT_components_refresh_propgroups_current(Operator): - """Update UI values from custom properties to CURRENT object""" - bl_idname = "object.refresh_ui_from_custom_properties_current" - bl_label = "Apply custom_properties to current object" - bl_options = {"UNDO"} - - @classmethod - def register(cls): - bpy.types.WindowManager.components_from_custom_properties_progress = bpy.props.FloatProperty(default=-1.0) #bpy.props.PointerProperty(type=RenameHelper) - - @classmethod - def unregister(cls): - del bpy.types.WindowManager.components_from_custom_properties_progress - - def execute(self, context): - print("apply custom properties to current object") - object = context.object - error = False - try: - apply_customProperty_values_to_item_propertyGroups(object) - progress = 0.5 - context.window_manager.components_from_custom_properties_progress = progress - try: - # now force refresh the ui - bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) - except:pass # ony run in ui - - except Exception as error_message: - del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure - error = True - self.report({'ERROR'}, "Failed to update propertyGroup values from custom property: Error:" + str(error_message)) - if not error: - self.report({'INFO'}, "Sucessfully generated UI values for custom properties for selected object") - context.window_manager.components_from_custom_properties_progress = -1.0 - - return {'FINISHED'} - - -class BLENVY_OT_components_refresh_propgroups_all(Operator): - """Update UI values from custom properties to ALL object""" - bl_idname = "object.refresh_ui_from_custom_properties_all" - bl_label = "Apply custom_properties to all objects" - bl_options = {"UNDO"} - - @classmethod - def register(cls): - bpy.types.WindowManager.components_from_custom_properties_progress_all = bpy.props.FloatProperty(default=-1.0) #bpy.props.PointerProperty(type=RenameHelper) - - @classmethod - def unregister(cls): - del bpy.types.WindowManager.components_from_custom_properties_progress_all - - def execute(self, context): - print("apply custom properties to all object") - bpy.context.window_manager.components_registry.disable_all_object_updates = True - errors = [] - total = len(bpy.data.objects) - - for index, object in enumerate(bpy.data.objects): - - try: - apply_customProperty_values_to_item_propertyGroups(object) - except Exception as error: - del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure - errors.append( "object: '" + object.name + "', error: " + str(error)) - - progress = index / total - context.window_manager.components_from_custom_properties_progress_all = progress - # now force refresh the ui - bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) - - - - if len(errors) > 0: - self.report({'ERROR'}, "Failed to update propertyGroup values from custom property: Errors:" + str(errors)) - else: - self.report({'INFO'}, "Sucessfully generated UI values for custom properties for all objects") - bpy.context.window_manager.components_registry.disable_all_object_updates = False - context.window_manager.components_from_custom_properties_progress_all = -1.0 - return {'FINISHED'} class BLENVY_OT_components_registry_browse_schema(Operator, ImportHelper): """Browse for registry json file""" diff --git a/tools/blenvy/add_ons/bevy_components/utils.py b/tools/blenvy/add_ons/bevy_components/utils.py index 5f45e31..2eefc8e 100644 --- a/tools/blenvy/add_ons/bevy_components/utils.py +++ b/tools/blenvy/add_ons/bevy_components/utils.py @@ -1,7 +1,14 @@ import bpy from .constants import HIDDEN_COMPONENTS -from bpy.props import StringProperty +from bpy.props import StringProperty, EnumProperty from bpy_types import Operator +from blenvy.core.helpers_collections import (set_active_collection) + +def get_collection_scene(collection): + for scene in bpy.data.scenes: + if scene.user_of_id(collection): + return scene + return None #FIXME: does not work if object is hidden !! def get_selected_object_or_collection(context): @@ -15,12 +22,23 @@ def get_selected_object_or_collection(context): return target -class BLENVY_OT_object_select(Operator): +class BLENVY_OT_item_select(Operator): """Select object by name""" - bl_idname = "object.select" - bl_label = "Select object" + bl_idname = "blenvy.select_item" + bl_label = "Select item (object or collection)" bl_options = {"UNDO"} + + item_type : EnumProperty( + name="item type", + description="type of the item to select: object or collection", + items=( + ('OBJECT', "Object", ""), + ('COLLECTION', "Collection", ""), + ), + default="OBJECT" + ) # type: ignore + target_name: StringProperty( name="target name", description="target to select's name ", @@ -28,13 +46,24 @@ class BLENVY_OT_object_select(Operator): def execute(self, context): if self.target_name: - object = bpy.data.objects[self.target_name] - scenes_of_object = list(object.users_scene) - if len(scenes_of_object) > 0: - bpy.ops.object.select_all(action='DESELECT') - bpy.context.window.scene = scenes_of_object[0] - object.select_set(True) - bpy.context.view_layer.objects.active = object + if self.item_type == "OBJECT": + object = bpy.data.objects[self.target_name] + scenes_of_object = list(object.users_scene) + if len(scenes_of_object) > 0: + bpy.ops.object.select_all(action='DESELECT') + bpy.context.window.scene = scenes_of_object[0] + object.select_set(True) + bpy.context.view_layer.objects.active = object + elif self.item_type == "COLLECTION": + collection = bpy.data.collections[self.target_name] + scene_of_collection = get_collection_scene(collection) + if scene_of_collection is not None: + bpy.ops.object.select_all(action='DESELECT') + bpy.context.window.scene = scene_of_collection + bpy.context.view_layer.objects.active = None + set_active_collection(bpy.context.window.scene, collection.name) + + return {'FINISHED'} @@ -45,7 +74,6 @@ def get_selection_type(selection): return 'Collection' def add_component_to_ui_list(self, context, _): - print("add components to ui_list") items = [] type_infos = context.window_manager.components_registry.type_infos for long_name in type_infos.keys(): diff --git a/tools/blenvy/blueprints/operators.py b/tools/blenvy/blueprints/operators.py index b477250..92ec234 100644 --- a/tools/blenvy/blueprints/operators.py +++ b/tools/blenvy/blueprints/operators.py @@ -22,18 +22,12 @@ class BLENVY_OT_blueprint_select(Operator): def execute(self, context): if self.blueprint_collection_name: - collection = bpy.data.collections[self.blueprint_collection_name] scene = bpy.data.scenes[self.blueprint_scene_name] if scene: bpy.ops.object.select_all(action='DESELECT') bpy.context.window.scene = scene bpy.context.view_layer.objects.active = None set_active_collection(scene, self.blueprint_collection_name) - #bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children[self.blueprint_collection_name] - #bpy.context.view_layer.collections.active = collection - # bpy.context.view_layer.active_layer_collection = collection - """for o in collection.objects: - o.select_set(True)""" return {'FINISHED'} \ No newline at end of file