mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-12-28 02:24:10 +00:00
feat(Blenvy): huge improvements to components UI:
* removed obsolete / overly complex pieces of UI * complete rework of component selections: much nicer, searchable, simpler ui * main component selector & per "error" component selectors , as well as bulk replace ones are now all independant * overhauled a lot of helpers to work with both objects & collections * reworked ui ordering for upgrade/ rename * more clearer status display for invalid components * etc etc
This commit is contained in:
parent
295c387132
commit
9cb0c6262e
@ -43,7 +43,7 @@ Blueprints:
|
|||||||
- [x] on save: write IN THE COLLECTION PROPERTIES
|
- [x] on save: write IN THE COLLECTION PROPERTIES
|
||||||
- list of assets
|
- list of assets
|
||||||
- export path
|
- export path
|
||||||
- [ ] blueprint selection for nested blueprints is broken
|
- [x] blueprint selection for nested blueprints is broken
|
||||||
|
|
||||||
- [ ] scan & inject on load
|
- [ ] scan & inject on load
|
||||||
- [ ] scan & inject on save
|
- [ ] scan & inject on save
|
||||||
@ -58,7 +58,7 @@ Components:
|
|||||||
- [ ] OT_rename_component
|
- [ ] OT_rename_component
|
||||||
- [ ] Fix_Component_Operator
|
- [ ] Fix_Component_Operator
|
||||||
- [ ] add handling for core::ops::Range<f32> & other ranges
|
- [ ] add handling for core::ops::Range<f32> & other ranges
|
||||||
- [ ] fix is_component_valid that is used in gltf_auto_export
|
- [x] fix is_component_valid that is used in gltf_auto_export
|
||||||
- Hashmap Support
|
- Hashmap Support
|
||||||
- [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side
|
- [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side
|
||||||
- [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
|
- [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
|
||||||
@ -69,6 +69,16 @@ Components:
|
|||||||
- [x] move saveable settings out to a settings file
|
- [x] move saveable settings out to a settings file
|
||||||
- [x] update save & load
|
- [x] update save & load
|
||||||
- [x] add handling of polling frequency & enabling
|
- [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
|
||||||
|
- 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
|
||||||
|
-> see in registry ui "for custom_property in object.keys():"
|
||||||
|
|
||||||
|
- [x] overhaul / improve the component selector (with built in searching, etc)
|
||||||
|
- [ ] remove select_component_name_to_replace
|
||||||
|
|
||||||
|
|
||||||
General things to solve:
|
General things to solve:
|
||||||
@ -124,7 +134,9 @@ General issues:
|
|||||||
|
|
||||||
- [x] remove BlueprintsList & replace is with assets list
|
- [x] remove BlueprintsList & replace is with assets list
|
||||||
- [ ] update main docs
|
- [ ] update main docs
|
||||||
|
- [ ] rename project to Blenvy
|
||||||
- [ ] replace all references to the old 2 add-ons with those to Blenvy
|
- [ ] replace all references to the old 2 add-ons with those to Blenvy
|
||||||
- [ ] rename repo to "Blenvy"
|
- [ ] rename repo to "Blenvy"
|
||||||
|
|
||||||
|
|
||||||
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
|
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
|
@ -24,7 +24,6 @@ from .add_ons.bevy_components.registry.ui import (BEVY_COMPONENTS_PT_Configurati
|
|||||||
from .add_ons.bevy_components.components.metadata import (ComponentMetadata, ComponentsMeta)
|
from .add_ons.bevy_components.components.metadata import (ComponentMetadata, ComponentsMeta)
|
||||||
from .add_ons.bevy_components.components.lists import GENERIC_LIST_OT_actions, Generic_LIST_OT_AddItem, Generic_LIST_OT_RemoveItem, Generic_LIST_OT_SelectItem
|
from .add_ons.bevy_components.components.lists import GENERIC_LIST_OT_actions, Generic_LIST_OT_AddItem, Generic_LIST_OT_RemoveItem, Generic_LIST_OT_SelectItem
|
||||||
from .add_ons.bevy_components.components.maps import GENERIC_MAP_OT_actions
|
from .add_ons.bevy_components.components.maps import GENERIC_MAP_OT_actions
|
||||||
from .add_ons.bevy_components.components.definitions_list import (ComponentDefinitionsList, ClearComponentDefinitionsList)
|
|
||||||
from .add_ons.bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
|
from .add_ons.bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
|
||||||
from .add_ons.bevy_components.settings import ComponentsSettings
|
from .add_ons.bevy_components.settings import ComponentsSettings
|
||||||
|
|
||||||
@ -81,9 +80,6 @@ classes = [
|
|||||||
GenerateComponent_From_custom_property_Operator,
|
GenerateComponent_From_custom_property_Operator,
|
||||||
Toggle_ComponentVisibility,
|
Toggle_ComponentVisibility,
|
||||||
|
|
||||||
ComponentDefinitionsList,
|
|
||||||
ClearComponentDefinitionsList,
|
|
||||||
|
|
||||||
ComponentMetadata,
|
ComponentMetadata,
|
||||||
ComponentsMeta,
|
ComponentsMeta,
|
||||||
MissingBevyType,
|
MissingBevyType,
|
||||||
@ -103,6 +99,7 @@ classes = [
|
|||||||
BEVY_COMPONENTS_PT_ComponentsPanel,
|
BEVY_COMPONENTS_PT_ComponentsPanel,
|
||||||
BEVY_COMPONENTS_PT_AdvancedToolsPanel,
|
BEVY_COMPONENTS_PT_AdvancedToolsPanel,
|
||||||
#BEVY_COMPONENTS_PT_Configuration,
|
#BEVY_COMPONENTS_PT_Configuration,
|
||||||
|
|
||||||
MISSING_TYPES_UL_List,
|
MISSING_TYPES_UL_List,
|
||||||
BEVY_COMPONENTS_PT_MissingTypesPanel,
|
BEVY_COMPONENTS_PT_MissingTypesPanel,
|
||||||
|
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
import bpy
|
import bpy
|
||||||
from blenvy.core.object_makers import (make_empty)
|
from blenvy.core.object_makers import (make_empty)
|
||||||
|
from blenvy.add_ons.bevy_components.utils import is_component_valid_and_enabled
|
||||||
from ..constants import custom_properties_to_filter_out
|
from ..constants import custom_properties_to_filter_out
|
||||||
|
|
||||||
def is_component_valid_and_enabled(object, component_name):
|
|
||||||
if "components_meta" in object or hasattr(object, "components_meta"):
|
|
||||||
target_components_metadata = object.components_meta.components
|
|
||||||
component_meta = next(filter(lambda component: component["long_name"] == component_name, target_components_metadata), None)
|
|
||||||
if component_meta != None:
|
|
||||||
return component_meta.enabled and not component_meta.invalid
|
|
||||||
return True
|
|
||||||
|
|
||||||
def remove_unwanted_custom_properties(object):
|
def remove_unwanted_custom_properties(object):
|
||||||
to_remove = []
|
to_remove = []
|
||||||
component_names = list(object.keys()) # to avoid 'IDPropertyGroup changed size during iteration' issues
|
component_names = list(object.keys()) # to avoid 'IDPropertyGroup changed size during iteration' issues
|
||||||
|
@ -39,14 +39,14 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out
|
|||||||
add_scene_property(temp_scene, 'assets_components', {"AllAssets": f"AllAssets({all_assets})".replace("'", '')})
|
add_scene_property(temp_scene, 'assets_components', {"AllAssets": f"AllAssets({all_assets})".replace("'", '')})
|
||||||
|
|
||||||
# save active scene
|
# save active scene
|
||||||
original_scene = bpy.context.window.scene
|
active_scene = bpy.context.window.scene
|
||||||
# and selected collection
|
# and selected collection
|
||||||
original_collection = bpy.context.view_layer.active_layer_collection
|
active_collection = bpy.context.view_layer.active_layer_collection
|
||||||
# and mode
|
# and mode
|
||||||
original_mode = bpy.context.active_object.mode if bpy.context.active_object != None else None
|
active_mode = bpy.context.active_object.mode if bpy.context.active_object != None else None
|
||||||
# we change the mode to object mode, otherwise the gltf exporter is not happy
|
# we change the mode to object mode, otherwise the gltf exporter is not happy
|
||||||
if original_mode != None and original_mode != 'OBJECT':
|
if active_mode != None and active_mode != 'OBJECT':
|
||||||
print("setting to object mode", original_mode)
|
print("setting to object mode", active_mode)
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
# we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene
|
# we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene
|
||||||
bpy.context.window.scene = temp_scene
|
bpy.context.window.scene = temp_scene
|
||||||
@ -74,12 +74,12 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out
|
|||||||
tempScene_cleaner(temp_scene, scene_filler_data)
|
tempScene_cleaner(temp_scene, scene_filler_data)
|
||||||
|
|
||||||
# reset active scene
|
# reset active scene
|
||||||
bpy.context.window.scene = original_scene
|
bpy.context.window.scene = active_scene
|
||||||
# reset active collection
|
# reset active collection
|
||||||
bpy.context.view_layer.active_layer_collection = original_collection
|
bpy.context.view_layer.active_layer_collection = active_collection
|
||||||
# reset mode
|
# reset mode
|
||||||
if original_mode != None:
|
if active_mode is not None:
|
||||||
bpy.ops.object.mode_set( mode = original_mode )
|
bpy.ops.object.mode_set( mode = active_mode )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import bpy
|
|
||||||
from bpy.props import (StringProperty)
|
|
||||||
|
|
||||||
# this one is for UI only, and its inner list contains a useable list of shortnames of components
|
|
||||||
class ComponentDefinitionsList(bpy.types.PropertyGroup):
|
|
||||||
|
|
||||||
# FIXME: not sure, hard coded exclude list, feels wrong
|
|
||||||
exclude = ['Parent', 'Children']
|
|
||||||
|
|
||||||
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():
|
|
||||||
definition = type_infos[long_name]
|
|
||||||
short_name = definition["short_name"]
|
|
||||||
is_component = definition['isComponent'] if "isComponent" in definition else False
|
|
||||||
|
|
||||||
if self.filter in short_name and is_component:
|
|
||||||
if not 'Handle' in short_name and not "Cow" in short_name and not "AssetId" in short_name and short_name not in self.exclude: # FIXME: hard coded, seems wrong
|
|
||||||
items.append((long_name, short_name, long_name))
|
|
||||||
|
|
||||||
items.sort(key=lambda a: a[1])
|
|
||||||
return items
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def register(cls):
|
|
||||||
bpy.types.WindowManager.components_list = bpy.props.PointerProperty(type=ComponentDefinitionsList)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def unregister(cls):
|
|
||||||
del bpy.types.WindowManager.components_list
|
|
||||||
|
|
||||||
list : bpy.props.EnumProperty(
|
|
||||||
name="list",
|
|
||||||
description="list",
|
|
||||||
# items argument required to initialize, just filled with empty values
|
|
||||||
items = add_component_to_ui_list,
|
|
||||||
) # type: ignore
|
|
||||||
filter: StringProperty(
|
|
||||||
name="component filter",
|
|
||||||
description="filter for the components list",
|
|
||||||
options={'TEXTEDIT_UPDATE'}
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
class ClearComponentDefinitionsList(bpy.types.Operator):
|
|
||||||
''' clear list of bpy.context.collection.component_definitions '''
|
|
||||||
bl_label = "clear component definitions"
|
|
||||||
bl_idname = "components.clear_component_definitions"
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
# create a new item, assign its properties
|
|
||||||
bpy.context.collection.component_definitions.clear()
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
|
||||||
|
|
@ -4,6 +4,7 @@ from bpy_types import (PropertyGroup)
|
|||||||
|
|
||||||
from ..propGroups.conversions_from_prop_group import property_group_value_to_custom_property_value
|
from ..propGroups.conversions_from_prop_group import property_group_value_to_custom_property_value
|
||||||
from ..propGroups.conversions_to_prop_group import property_group_value_from_custom_property_value
|
from ..propGroups.conversions_to_prop_group import property_group_value_from_custom_property_value
|
||||||
|
from ..utils import add_component_to_ui_list
|
||||||
|
|
||||||
class ComponentMetadata(bpy.types.PropertyGroup):
|
class ComponentMetadata(bpy.types.PropertyGroup):
|
||||||
short_name : bpy.props.StringProperty(
|
short_name : bpy.props.StringProperty(
|
||||||
@ -43,6 +44,8 @@ class ComponentMetadata(bpy.types.PropertyGroup):
|
|||||||
default=True
|
default=True
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentsMeta(PropertyGroup):
|
class ComponentsMeta(PropertyGroup):
|
||||||
infos_per_component: StringProperty(
|
infos_per_component: StringProperty(
|
||||||
name="infos per component",
|
name="infos per component",
|
||||||
@ -50,6 +53,12 @@ class ComponentsMeta(PropertyGroup):
|
|||||||
) # type: ignore
|
) # type: ignore
|
||||||
components: bpy.props.CollectionProperty(type = ComponentMetadata) # type: ignore
|
components: bpy.props.CollectionProperty(type = ComponentMetadata) # type: ignore
|
||||||
|
|
||||||
|
# compone
|
||||||
|
component_selector: StringProperty(
|
||||||
|
search=add_component_to_ui_list
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
# you can add components to both objects & collections
|
# you can add components to both objects & collections
|
||||||
|
@ -198,7 +198,7 @@ class RemoveComponentFromAllItemsOperator(Operator):
|
|||||||
|
|
||||||
class RenameHelper(bpy.types.PropertyGroup):
|
class RenameHelper(bpy.types.PropertyGroup):
|
||||||
original_name: bpy.props.StringProperty(name="") # type: ignore
|
original_name: bpy.props.StringProperty(name="") # type: ignore
|
||||||
new_name: bpy.props.StringProperty(name="") # type: ignore
|
target_name: bpy.props.StringProperty(name="") # type: ignore
|
||||||
|
|
||||||
#object: bpy.props.PointerProperty(type=bpy.types.Object)
|
#object: bpy.props.PointerProperty(type=bpy.types.Object)
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -217,12 +217,12 @@ class OT_rename_component(Operator):
|
|||||||
bl_options = {"UNDO"}
|
bl_options = {"UNDO"}
|
||||||
|
|
||||||
original_name: bpy.props.StringProperty(default="") # type: ignore
|
original_name: bpy.props.StringProperty(default="") # type: ignore
|
||||||
new_name: StringProperty(
|
target_name: StringProperty(
|
||||||
name="new_name",
|
name="target_name",
|
||||||
description="new name of component",
|
description="new name of component",
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
target_objects: bpy.props.StringProperty() # type: ignore
|
target_items: bpy.props.StringProperty() # type: ignore
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
@ -237,28 +237,28 @@ class OT_rename_component(Operator):
|
|||||||
type_infos = registry.type_infos
|
type_infos = registry.type_infos
|
||||||
settings = context.window_manager.bevy_component_rename_helper
|
settings = context.window_manager.bevy_component_rename_helper
|
||||||
original_name = settings.original_name if self.original_name == "" else self.original_name
|
original_name = settings.original_name if self.original_name == "" else self.original_name
|
||||||
new_name = self.new_name
|
target_name = self.target_name
|
||||||
|
|
||||||
|
|
||||||
print("renaming components: original name", original_name, "new_name", self.new_name, "targets", self.target_objects)
|
print("renaming components: original name", original_name, "target_name", self.target_name, "targets", self.target_items)
|
||||||
target_objects = json.loads(self.target_objects)
|
target_items = json.loads(self.target_items)
|
||||||
errors = []
|
errors = []
|
||||||
total = len(target_objects)
|
total = len(target_items)
|
||||||
|
|
||||||
if original_name != '' and new_name != '' and original_name != new_name and len(target_objects) > 0:
|
if original_name != '' and target_name != '' and original_name != target_name and len(target_items) > 0:
|
||||||
for index, item_name in enumerate(target_objects):
|
for index, item_name in enumerate(target_items):
|
||||||
object = bpy.data.objects[item_name]
|
object = bpy.data.objects[item_name]
|
||||||
if object and original_name in get_bevy_components(object) or original_name in object:
|
if object and original_name in get_bevy_components(object) or original_name in object:
|
||||||
try:
|
try:
|
||||||
# attempt conversion
|
# attempt conversion
|
||||||
rename_component(object=object, original_long_name=original_name, new_long_name=new_name)
|
rename_component(item=object, original_long_name=original_name, new_long_name=target_name)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
if '__disable__update' in object:
|
if '__disable__update' in object:
|
||||||
del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure
|
del object["__disable__update"] # make sure custom properties are updateable afterwards, even in the case of failure
|
||||||
components_metadata = getattr(object, "components_meta", None)
|
components_metadata = getattr(object, "components_meta", None)
|
||||||
if components_metadata:
|
if components_metadata:
|
||||||
components_metadata = components_metadata.components
|
components_metadata = components_metadata.components
|
||||||
component_meta = next(filter(lambda component: component["long_name"] == new_name, components_metadata), None)
|
component_meta = next(filter(lambda component: component["long_name"] == target_name, components_metadata), None)
|
||||||
if component_meta:
|
if component_meta:
|
||||||
component_meta.invalid = True
|
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"
|
component_meta.invalid_details = "wrong custom property value, overwrite them by changing the values in the ui or change them & regenerate"
|
||||||
|
@ -172,7 +172,7 @@ class BEVY_COMPONENTS_PT_ComponentsPanel(bpy.types.Panel):
|
|||||||
# name = context.object.name if context.object != None else ''
|
# name = context.object.name if context.object != None else ''
|
||||||
layout.label(text=f"Components for {name} ({target_type})")
|
layout.label(text=f"Components for {name} ({target_type})")
|
||||||
|
|
||||||
print("object", context.object, "active", context.active_object, "objects", context.selected_objects)
|
#print("object", context.object, "active", context.active_object, "objects", context.selected_objects)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
object = next(iter(context.selected_objects), None)
|
object = next(iter(context.selected_objects), None)
|
||||||
@ -181,28 +181,27 @@ class BEVY_COMPONENTS_PT_ComponentsPanel(bpy.types.Panel):
|
|||||||
|
|
||||||
# we get & load our component registry
|
# we get & load our component registry
|
||||||
registry = bpy.context.window_manager.components_registry
|
registry = bpy.context.window_manager.components_registry
|
||||||
available_components = bpy.context.window_manager.components_list
|
selected_component = bpy.context.window_manager.blenvy.components.component_selector
|
||||||
registry_has_type_infos = registry.has_type_infos()
|
registry_has_type_infos = registry.has_type_infos()
|
||||||
|
|
||||||
if object is not None:
|
if object is not None:
|
||||||
draw_component_ui(layout, object, registry, available_components, registry_has_type_infos, context)
|
draw_component_ui(layout, object, registry, selected_component, registry_has_type_infos, context)
|
||||||
elif collection is not None:
|
elif collection is not None:
|
||||||
draw_component_ui(layout, collection, registry, available_components, registry_has_type_infos, context)
|
draw_component_ui(layout, collection, registry, selected_component, registry_has_type_infos, context)
|
||||||
else:
|
else:
|
||||||
layout.label(text ="Select an object to edit its components")
|
layout.label(text ="Select an object to edit its components")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def draw_component_ui(layout, object_or_collection, registry, available_components, registry_has_type_infos, context):
|
def draw_component_ui(layout, object_or_collection, registry, selected_component, registry_has_type_infos, context):
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.prop(available_components, "list", text="Component")
|
row.prop(context.window_manager.blenvy.components, "component_selector", text="Component: ")
|
||||||
row.prop(available_components, "filter",text="Filter")
|
|
||||||
|
|
||||||
# add components
|
# add components
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
op = row.operator(AddComponentOperator.bl_idname, text="Add", icon="ADD")
|
op = row.operator(AddComponentOperator.bl_idname, text="Add", icon="ADD")
|
||||||
op.component_type = available_components.list
|
op.component_type = selected_component
|
||||||
row.enabled = available_components.list != ''
|
row.enabled = selected_component != ''
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@ -249,7 +248,6 @@ def draw_component_ui(layout, object_or_collection, registry, available_componen
|
|||||||
# we fetch the matching ui property group
|
# we fetch the matching ui property group
|
||||||
root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name)
|
root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name)
|
||||||
"""print("root_propertyGroup_name", root_propertyGroup_name)"""
|
"""print("root_propertyGroup_name", root_propertyGroup_name)"""
|
||||||
print("component_meta", component_meta, component_invalid)
|
|
||||||
|
|
||||||
if root_propertyGroup_name:
|
if root_propertyGroup_name:
|
||||||
propertyGroup = getattr(component_meta, root_propertyGroup_name, None)
|
propertyGroup = getattr(component_meta, root_propertyGroup_name, None)
|
||||||
|
2
tools/blenvy/add_ons/bevy_components/constants.py
Normal file
2
tools/blenvy/add_ons/bevy_components/constants.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# FIXME: not sure, hard coded exclude list ?
|
||||||
|
HIDDEN_COMPONENTS = ['Parent', 'Children']
|
@ -69,7 +69,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return context.window_manager.blenvy.mode == 'TOOLS'
|
return context.window_manager.blenvy.mode == 'COMPONENTS'
|
||||||
|
|
||||||
def draw_invalid_or_unregistered_header(self, layout, items):
|
def draw_invalid_or_unregistered_header(self, layout, items):
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
@ -78,17 +78,13 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
|
|||||||
col = row.column()
|
col = row.column()
|
||||||
col.label(text=item)
|
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):
|
||||||
available_components = bpy.context.window_manager.components_list
|
|
||||||
registry = bpy.context.window_manager.components_registry
|
registry = bpy.context.window_manager.components_registry
|
||||||
registry_has_type_infos = registry.has_type_infos()
|
registry_has_type_infos = registry.has_type_infos()
|
||||||
|
selected_component = target.components_meta.component_selector
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
|
||||||
col = row.column()
|
|
||||||
col.label(text=component_name)
|
|
||||||
|
|
||||||
col = row.column()
|
col = row.column()
|
||||||
operator = col.operator("object.select", text=target.name)
|
operator = col.operator("object.select", text=target.name)
|
||||||
operator.target_name = target.name
|
operator.target_name = target.name
|
||||||
@ -97,15 +93,21 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
|
|||||||
col.label(text=status)
|
col.label(text=status)
|
||||||
|
|
||||||
col = row.column()
|
col = row.column()
|
||||||
col.prop(available_components, "list", text="")
|
col.label(text=component_name)
|
||||||
|
|
||||||
|
col = row.column()
|
||||||
|
# each components_meta has a component selector to pick components from
|
||||||
|
components_meta = target.components_meta
|
||||||
|
col.prop(components_meta, "component_selector", text="")
|
||||||
|
|
||||||
|
|
||||||
col = row.column()
|
col = row.column()
|
||||||
operator = col.operator("object.rename_bevy_component", text="", icon="SHADERFX") #rename
|
operator = col.operator("object.rename_bevy_component", text="", icon="SHADERFX") #rename
|
||||||
new_name = registry.type_infos[available_components.list]['long_name'] if available_components.list in registry.type_infos else ""
|
target_name = registry.type_infos[selected_component]['long_name'] if selected_component in registry.type_infos else ""
|
||||||
operator.original_name = component_name
|
operator.original_name = component_name
|
||||||
operator.target_objects = json.dumps([target.name])
|
operator.target_items = json.dumps([target.name])
|
||||||
operator.new_name = new_name
|
operator.target_name = target_name
|
||||||
col.enabled = registry_has_type_infos and component_name != "" and component_name != new_name
|
col.enabled = registry_has_type_infos and component_name != "" and component_name != target_name
|
||||||
|
|
||||||
|
|
||||||
col = row.column()
|
col = row.column()
|
||||||
@ -115,84 +117,100 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
|
|||||||
operator.item_type = get_selection_type(target)
|
operator.item_type = get_selection_type(target)
|
||||||
|
|
||||||
|
|
||||||
col = row.column()
|
"""col = row.column()
|
||||||
col = row.column()
|
col = row.column()
|
||||||
operator = col.operator("object.select_component_name_to_replace", text="", icon="EYEDROPPER") #text="select for rename",
|
operator = col.operator("object.select_component_name_to_replace", text="", icon="EYEDROPPER") #text="select for rename",
|
||||||
operator.component_name = component_name
|
operator.component_name = component_name"""
|
||||||
|
|
||||||
|
def draw_invalid_item_entry(self, layout, item, invalid_component_names, items_with_invalid_components):
|
||||||
|
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)
|
||||||
|
|
||||||
|
if not item.name in items_with_invalid_components:
|
||||||
|
items_with_invalid_components.append(item.name)
|
||||||
|
|
||||||
|
if not long_name in invalid_component_names:
|
||||||
|
invalid_component_names.append(long_name)
|
||||||
|
|
||||||
|
|
||||||
|
object_component_names.append(long_name)
|
||||||
|
|
||||||
|
for custom_property in item.keys():
|
||||||
|
# Invalid (something is wrong)
|
||||||
|
# Unregistered (not in registry)
|
||||||
|
# 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:
|
||||||
|
status = "Upgrade Needed"
|
||||||
|
|
||||||
|
if status is not None:
|
||||||
|
self.draw_invalid_or_unregistered(layout, status, custom_property, item)
|
||||||
|
|
||||||
|
if not item.name in items_with_invalid_components:
|
||||||
|
items_with_invalid_components.append(item.name)
|
||||||
|
"""if not long_name in invalid_component_names:
|
||||||
|
invalid_component_names.append(custom_property)""" # FIXME
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
registry = bpy.context.window_manager.components_registry
|
registry = bpy.context.window_manager.components_registry
|
||||||
registry_has_type_infos = registry.has_type_infos()
|
registry_has_type_infos = registry.has_type_infos()
|
||||||
selected_object = context.selected_objects[0] if len(context.selected_objects) > 0 else None
|
selected_object = context.selected_objects[0] if len(context.selected_objects) > 0 else None
|
||||||
available_components = bpy.context.window_manager.components_list
|
selected_component = bpy.context.window_manager.blenvy.components.component_selector
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
box= row.box()
|
box= row.box()
|
||||||
box.label(text="Invalid/ unregistered components")
|
box.label(text="Invalid/ unregistered components")
|
||||||
|
|
||||||
objects_with_invalid_components = []
|
items_with_invalid_components = []
|
||||||
invalid_component_names = []
|
invalid_component_names = []
|
||||||
|
|
||||||
self.draw_invalid_or_unregistered_header(layout, ["Component", "Object", "Status", "Target"])
|
self.draw_invalid_or_unregistered_header(layout, ["Item","Status", "Component", "Target"])
|
||||||
|
|
||||||
for object in bpy.data.objects: # TODO: very inneficent
|
for object in bpy.data.objects: # TODO: very inneficent
|
||||||
if len(object.keys()) > 0:
|
if len(object.keys()) > 0:
|
||||||
if "components_meta" in object:
|
self.draw_invalid_item_entry(layout, object, invalid_component_names, items_with_invalid_components)
|
||||||
components_metadata = object.components_meta.components
|
|
||||||
comp_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, object)
|
|
||||||
|
|
||||||
if not object.name in objects_with_invalid_components:
|
for collection in bpy.data.collections:
|
||||||
objects_with_invalid_components.append(object.name)
|
if len(collection.keys()) > 0:
|
||||||
|
self.draw_invalid_item_entry(layout, collection, invalid_component_names, items_with_invalid_components)
|
||||||
if not long_name in invalid_component_names:
|
|
||||||
invalid_component_names.append(long_name)
|
|
||||||
|
|
||||||
|
|
||||||
comp_names.append(long_name)
|
|
||||||
|
|
||||||
for custom_property in object.keys():
|
|
||||||
if custom_property != 'components_meta' and custom_property != 'bevy_components' and custom_property not in comp_names:
|
|
||||||
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)
|
|
||||||
"""if not long_name in invalid_component_names:
|
|
||||||
invalid_component_names.append(custom_property)""" # FIXME
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.separator()
|
layout.separator()
|
||||||
original_name = bpy.context.window_manager.bevy_component_rename_helper.original_name
|
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 = layout.row()
|
||||||
col = row.column()
|
col = row.column()
|
||||||
col.label(text="Original")
|
col.label(text="Component")
|
||||||
col = row.column()
|
col = row.column()
|
||||||
col.label(text="New")
|
col.label(text="Target")
|
||||||
col = row.column()
|
col = row.column()
|
||||||
col.label(text="------")
|
col.label(text="------")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
col = row.column()
|
col = row.column()
|
||||||
box = col.box()
|
col.prop(bpy.context.window_manager.blenvy.components, "source_component_selector", text="")
|
||||||
box.label(text=original_name)
|
|
||||||
|
|
||||||
col = row.column()
|
col = row.column()
|
||||||
col.prop(available_components, "list", text="")
|
col.prop(bpy.context.window_manager.blenvy.components, "target_component_selector", text="")
|
||||||
#row.prop(available_components, "filter",text="Filter")
|
|
||||||
|
|
||||||
col = row.column()
|
col = row.column()
|
||||||
components_rename_progress = context.window_manager.components_rename_progress
|
components_rename_progress = context.window_manager.components_rename_progress
|
||||||
|
print("components_rename_progress", components_rename_progress)
|
||||||
if components_rename_progress == -1.0:
|
if components_rename_progress == -1.0:
|
||||||
operator = col.operator(OT_rename_component.bl_idname, text="apply", icon="SHADERFX")
|
operator = col.operator(OT_rename_component.bl_idname, text="apply", icon="SHADERFX")
|
||||||
operator.target_objects = json.dumps(objects_with_invalid_components)
|
operator.target_items = json.dumps(items_with_invalid_components)
|
||||||
new_name = registry.type_infos[available_components.list]['short_name'] if available_components.list in registry.type_infos else ""
|
operator.target_name = target_name
|
||||||
operator.new_name = new_name
|
col.enabled = registry_has_type_infos and original_name != "" and original_name != target_name
|
||||||
col.enabled = registry_has_type_infos and original_name != "" and original_name != new_name
|
|
||||||
else:
|
else:
|
||||||
if hasattr(layout,"progress") : # only for Blender > 4.0
|
if hasattr(layout,"progress") : # only for Blender > 4.0
|
||||||
col.progress(factor = components_rename_progress, text=f"updating {components_rename_progress * 100.0:.2f}%")
|
col.progress(factor = components_rename_progress, text=f"updating {components_rename_progress * 100.0:.2f}%")
|
||||||
@ -208,7 +226,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
|
|||||||
col.progress(factor = remove_components_progress, text=f"updating {remove_components_progress * 100.0:.2f}%")
|
col.progress(factor = remove_components_progress, text=f"updating {remove_components_progress * 100.0:.2f}%")
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
layout.separator()
|
"""layout.separator()
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
box= row.box()
|
box= row.box()
|
||||||
box.label(text="Conversions between custom properties and components & vice-versa")
|
box.label(text="Conversions between custom properties and components & vice-versa")
|
||||||
@ -266,7 +284,7 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
|
|||||||
if hasattr(layout,"progress") : # only for Blender > 4.0
|
if hasattr(layout,"progress") : # only for Blender > 4.0
|
||||||
layout.progress(factor = components_from_custom_properties_progress_all, text=f"updating {components_from_custom_properties_progress_all * 100.0:.2f}%")
|
layout.progress(factor = components_from_custom_properties_progress_all, text=f"updating {components_from_custom_properties_progress_all * 100.0:.2f}%")
|
||||||
|
|
||||||
|
"""
|
||||||
class BEVY_COMPONENTS_PT_MissingTypesPanel(bpy.types.Panel):
|
class BEVY_COMPONENTS_PT_MissingTypesPanel(bpy.types.Panel):
|
||||||
"""panel listing all the missing bevy types in the schema"""
|
"""panel listing all the missing bevy types in the schema"""
|
||||||
bl_idname = "BEVY_COMPONENTS_PT_MissingTypesPanel"
|
bl_idname = "BEVY_COMPONENTS_PT_MissingTypesPanel"
|
||||||
@ -340,3 +358,4 @@ class MISSING_TYPES_UL_List(UIList):
|
|||||||
layout.alignment = 'CENTER'
|
layout.alignment = 'CENTER'
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(item, "long_name", text="")
|
row.prop(item, "long_name", text="")
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProper
|
|||||||
from blenvy.settings import load_settings, upsert_settings, generate_complete_settings_dict
|
from blenvy.settings import load_settings, upsert_settings, generate_complete_settings_dict
|
||||||
from .propGroups.prop_groups import generate_propertyGroups_for_components
|
from .propGroups.prop_groups import generate_propertyGroups_for_components
|
||||||
from .components.metadata import ensure_metadata_for_all_items
|
from .components.metadata import ensure_metadata_for_all_items
|
||||||
|
from .utils import add_component_to_ui_list
|
||||||
|
|
||||||
# list of settings we do NOT want to save
|
# list of settings we do NOT want to save
|
||||||
settings_black_list = ['settings_save_enabled', 'watcher_active']
|
settings_black_list = ['settings_save_enabled', 'watcher_active']
|
||||||
@ -52,7 +53,6 @@ def watch_schema():
|
|||||||
pass
|
pass
|
||||||
return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None
|
return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None
|
||||||
|
|
||||||
|
|
||||||
class ComponentsSettings(PropertyGroup):
|
class ComponentsSettings(PropertyGroup):
|
||||||
|
|
||||||
settings_save_path = ".blenvy_components_settings" # where to store data in bpy.texts
|
settings_save_path = ".blenvy_components_settings" # where to store data in bpy.texts
|
||||||
@ -91,6 +91,20 @@ class ComponentsSettings(PropertyGroup):
|
|||||||
)# type: ignore
|
)# type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
component_selector: StringProperty(
|
||||||
|
search=add_component_to_ui_list
|
||||||
|
)# type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
source_component_selector: StringProperty(
|
||||||
|
search=add_component_to_ui_list
|
||||||
|
)# type: ignore
|
||||||
|
|
||||||
|
target_component_selector: StringProperty(
|
||||||
|
search=add_component_to_ui_list
|
||||||
|
)# type: ignore
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
pass
|
pass
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import bpy
|
import bpy
|
||||||
|
from .constants import HIDDEN_COMPONENTS
|
||||||
|
|
||||||
#FIXME: does not work if object is hidden !!
|
#FIXME: does not work if object is hidden !!
|
||||||
def get_selected_object_or_collection(context):
|
def get_selected_object_or_collection(context):
|
||||||
@ -16,3 +17,26 @@ def get_selection_type(selection):
|
|||||||
return 'Object'
|
return 'Object'
|
||||||
if isinstance(selection, bpy.types.Collection):
|
if isinstance(selection, bpy.types.Collection):
|
||||||
return 'Collection'
|
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():
|
||||||
|
definition = type_infos[long_name]
|
||||||
|
short_name = definition["short_name"]
|
||||||
|
is_component = definition['isComponent'] if "isComponent" in definition else False
|
||||||
|
"""if self.filter.lower() in short_name.lower() and is_component:"""
|
||||||
|
if not 'Handle' in short_name and not "Cow" in short_name and not "AssetId" in short_name and short_name not in HIDDEN_COMPONENTS: # FIXME: hard coded, seems wrong
|
||||||
|
items.append((long_name, short_name))
|
||||||
|
items.sort(key=lambda a: a[1])
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def is_component_valid_and_enabled(object, component_name):
|
||||||
|
if "components_meta" in object or hasattr(object, "components_meta"):
|
||||||
|
target_components_metadata = object.components_meta.components
|
||||||
|
component_meta = next(filter(lambda component: component["long_name"] == component_name, target_components_metadata), None)
|
||||||
|
if component_meta != None:
|
||||||
|
return component_meta.enabled and not component_meta.invalid
|
||||||
|
return True
|
Loading…
Reference in New Issue
Block a user