Blender_bevy_components_wor.../tools/blenvy/add_ons/bevy_components/utils.py

235 lines
9.7 KiB
Python

import json
import bpy
from bpy.props import StringProperty, EnumProperty
from bpy_types import Operator
from ...core.helpers_collections import set_active_collection
from .constants import HIDDEN_COMPONENTS
def select_area(context, area_name):
for area in context.screen.areas:
#if area.type == 'PROPERTIES' and context.object is not None and context.object.type not in ('LIGHT_PROBE', 'CAMERA', 'LIGHT', 'SPEAKER'):
# Set it the active space
#print("SELECT AREA", area_name)
try:
area.spaces.active.context = area_name #'MATERIAL' # 'VIEW_LAYER', 'SCENE' etc.
except Exception as error:
print(f"failed to switch to area {area_name}: {error}")
break # OPTIONAL
def get_collection_scene(collection):
for scene in bpy.data.scenes:
if scene.user_of_id(collection):
return scene
return None
def get_object_by_name(name):
object = bpy.data.objects.get(name, None)
return object
def get_object_scene(object):
object = bpy.data.objects.get(object.name, None)
if object is not None:
scenes_of_object = list(object.users_scene)
if len(scenes_of_object) > 0:
return scenes_of_object[0]
return None
def get_mesh_object(mesh):
for object in bpy.data.objects:
if isinstance(object.data, bpy.types.Mesh) and mesh.name == object.data.name:
return object
def get_material_object(material):
for object in bpy.data.objects:
if isinstance(object.data, bpy.types.Mesh) and material.name in object.data.materials:
return object
class BLENVY_OT_item_select(Operator):
"""Select object by name"""
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", ""),
('MESH', "Mesh", ""),
('MATERIAL', "Material", ""),
),
default="OBJECT"
) # type: ignore
target_name: StringProperty(
name="target name",
description="target to select's name ",
) # type: ignore
override_scene_name: StringProperty(
name="override scene name",
description="use this to override the scene selection mecanism",
default=""
) # type: ignore
@classmethod
def register(cls):
bpy.types.WindowManager.blenvy_item_selected_ids = StringProperty(default="{}")
@classmethod
def unregister(cls):
del bpy.types.WindowManager.blenvy_item_selected_ids
def execute(self, context):
if self.target_name:
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)
context.window_manager.blenvy_item_selected_ids = json.dumps({"name": object.name, "type": self.item_type})
bpy.context.view_layer.objects.active = object
select_area(context=context, area_name="OBJECT")
elif self.item_type == 'COLLECTION':
collection = bpy.data.collections[self.target_name]
scene_of_collection = get_collection_scene(collection) if self.override_scene_name == "" else bpy.data.scenes.get(self.override_scene_name, None)
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
context.window_manager.blenvy_item_selected_ids = json.dumps({"name": collection.name, "type": self.item_type})
set_active_collection(bpy.context.window.scene, collection.name)
#select_area(context=context, area_name="COLLECTION")
elif self.item_type == 'MESH':
mesh = bpy.data.meshes[self.target_name]
mesh_object = get_mesh_object(mesh)
scene_of_item = get_object_scene(mesh_object)
if scene_of_item is not None:
bpy.ops.object.select_all(action='DESELECT')
bpy.context.window.scene = scene_of_item
bpy.context.view_layer.objects.active = mesh_object
context.window_manager.blenvy_item_selected_ids = json.dumps({"name": mesh.name, "type": self.item_type})
select_area(context=context, area_name="DATA")
elif self.item_type == 'MATERIAL':
# find object that uses material
material = bpy.data.materials[self.target_name]
material_object = get_material_object(material)
scene_of_item = get_object_scene(material_object)
select_area(context=context, area_name="MATERIAL")
if scene_of_item is not None:
bpy.ops.object.select_all(action='DESELECT')
bpy.context.window.scene = scene_of_item
bpy.context.view_layer.objects.active = material_object
context.window_manager.blenvy_item_selected_ids = json.dumps({"name": material.name, "type": self.item_type})
select_area(context=context, area_name="MATERIAL")
return {'FINISHED'}
def get_selected_item(context):
selection = None
def get_outliner_area():
if bpy.context.area.type!='OUTLINER':
for area in bpy.context.screen.areas:
if area.type == 'OUTLINER':
return area
return None
#print("original context", context)
if selection is None:
area = get_outliner_area()
if area is not None:
region = next(region for region in area.regions if region.type == "WINDOW")
with bpy.context.temp_override(area=area, region=region):
#print("overriden context", bpy.context)
"""for obj in bpy.context.selected_ids:
print(f"Selected: {obj.name} - {type(obj)}")"""
number_of_selections = len(bpy.context.selected_ids)
selection = bpy.context.selected_ids[number_of_selections - 1] if number_of_selections > 0 else None #next(iter(bpy.context.selected_ids), None)
if selection is None:
number_of_selections = len(context.selected_objects)
selection = context.selected_objects[number_of_selections - 1] if number_of_selections > 0 else None
if selection is None:
try:
selection_overrides = json.loads(context.window_manager.blenvy_item_selected_ids)
#print("selection_overrides", selection_overrides)
if selection_overrides["type"] == "OBJECT":
selection = bpy.data.objects[selection_overrides["name"]]
elif selection_overrides["type"] == "COLLECTION":
selection = bpy.data.collections[selection_overrides["name"]]
if selection_overrides["type"] == "MESH":
selection = bpy.data.meshes[selection_overrides["name"]]
elif selection_overrides["type"] == "MATERIAL":
selection = bpy.data.materials[selection_overrides["name"]]
#print("SELECTION", selection)
#context.window_manager.blenvy_item_selected_ids = "{}"
except: pass
return selection
def get_selection_type(selection):
#print("bla mesh", isinstance(selection, bpy.types.Mesh), "bli bli", selection.type)
if isinstance(selection, bpy.types.Material):
return 'MATERIAL'
if isinstance(selection, bpy.types.Mesh):
return 'MESH'
if isinstance(selection, bpy.types.Object):
return 'OBJECT'
if isinstance(selection, bpy.types.Collection):
return 'COLLECTION'
def get_item_by_type(item_type, item_name):
item = None
if item_type == 'OBJECT':
item = bpy.data.objects[item_name]
elif item_type == 'COLLECTION':
item = bpy.data.collections[item_name]
elif item_type == "MESH":
item = bpy.data.meshes[item_name]
elif item_type == 'MATERIAL':
item = bpy.data.materials[item_name]
return item
def add_component_to_ui_list(self, context, _):
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 is_component and 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 is not None:
return component_meta.enabled and not component_meta.invalid
return True