def add_element(collection: T.bpy_prop_collection, proxy: Proxy, context: Context): """Add an element to a bpy_prop_collection using the collection specific API""" try: collection.add() except Exception: logger.error(f"add_element: failed for {collection}")
def add_element(collection: T.bpy_prop_collection, proxy: Proxy, index: int, context: Context): """Add an element to a bpy_prop_collection using the collection specific API.s""" if hasattr(collection, "add"): # either a bpy_prop_collection with an rna or a bpy_prop_collection_idprop try: collection.add() return except Exception as e: logger.error( f"add_element: call to add() failed for {context.visit_state.display_path()} ..." ) logger.error(f"... {e!r}") raise AddElementFailed from None if not hasattr(collection, "bl_rna"): # a bpy.types.bpy_prop_collection, e.g Pose.bones # We should not even attempt to add elements in these collections since they do not allow it at all. # However bpy_prop_collection and collections with an rna both managed by StructCollectionProxy. We need # proxy update to update the contents of existing elements, but it should not attempt to add/remove elements. # As a consequence, for attributes that fall into this category we trigger updates with additions and # deletions that are meaningless. Ignore them. # The right design could be to have different proxies for bpy_prop_collection and bpy_struct that behave like # collections. # see Proxy construction in read_attribute() return
def truncate_collection(target: T.bpy_prop_collection, proxy: Union[StructCollectionProxy, AosProxy], context: Context): """""" if not hasattr(target, "bl_rna"): return target_rna = target.bl_rna if any(isinstance(target_rna, t) for t in always_clear): target.clear() return if isinstance(target_rna, _resize_geometry_types): existing_length = len(target) incoming_length = proxy.length if existing_length != incoming_length: if existing_length != 0: logger.error(f"resize_geometry(): size mismatch for {target}") logger.error( f"... existing: {existing_length} incoming {incoming_length}" ) return logger.debug( f"resizing geometry: add({incoming_length}) for {target}") target.add(incoming_length) return if isinstance(target_rna, type(T.GPencilStrokePoints.bl_rna)): existing_length = len(target) incoming_length = proxy.length delta = incoming_length - existing_length if delta > 0: target.add(delta) else: while delta < 0: target.pop() delta += 1 return incoming_keys = set(proxy._data.keys()) existing_keys = set(target.keys()) truncate_keys = existing_keys - incoming_keys if not truncate_keys: return if isinstance(target_rna, type(T.KeyingSets.bl_rna)): for k in truncate_keys: target.active_index = target.find(k) bpy.ops.anim.keying_set_remove() else: try: for k in truncate_keys: target.remove(target[k]) except Exception: logger.warning( f"Not implemented truncate_collection for type {target.bl_rna} for {target} ..." ) for s in traceback.format_exc().splitlines(): logger.warning(f"...{s}")
def add_element(collection: T.bpy_prop_collection, proxy: Proxy, index: int, context: Context): """Add an element to a bpy_prop_collection using the collection specific API""" try: collection.bl_rna except AttributeError: return try: collection.add() except Exception: logger.error(f"add_element: failed for {collection}")
def _add_element_default(collection: T.bpy_prop_collection, proxy: Proxy, context: Context): try: return collection.add() except Exception: pass # try our best new_or_add = getattr(collection, "new", None) if new_or_add is None: new_or_add = getattr(collection, "add", None) if new_or_add is None: logger.warning(f"Not implemented new or add for {collection} ...") return None try: return new_or_add() except TypeError: try: key = proxy.data("name") return new_or_add(key) except Exception: logger.warning( f"Not implemented new or add for type {type(collection)} for {collection}[{key}] ..." ) for s in traceback.format_exc().splitlines(): logger.warning(f"...{s}") return None
def _add_element_keyingset(collection: T.bpy_prop_collection, proxy: Proxy, context: Context): # TODO current implementation fails # All keying sets paths have an empty name, and insertion with add() fails # with an empty name target_ref = proxy.data("id") if target_ref is None: target = None else: target = target_ref.target(context) data_path = proxy.data("data_path") index = proxy.data("array_index") group_method = proxy.data("group_method") group_name = proxy.data("group") return collection.add(target_id=target, data_path=data_path, index=index, group_method=group_method, group_name=group_name)
def fit_aos(target: T.bpy_prop_collection, proxy: AosProxy, context: Context): """ Adjust the size of a bpy_prop_collection proxified as an array of structures (e.g. MeshVertices) """ if not hasattr(target, "bl_rna"): return target_rna = target.bl_rna if isinstance(target_rna, _resize_geometry_types): existing_length = len(target) incoming_length = proxy.length if existing_length != incoming_length: if existing_length != 0: logger.error(f"resize_geometry(): size mismatch for {target}") logger.error( f"... existing: {existing_length} incoming {incoming_length}" ) return logger.debug( f"resizing geometry: add({incoming_length}) for {target}") target.add(incoming_length) return if isinstance(target_rna, type(T.GPencilStrokePoints.bl_rna)): existing_length = len(target) incoming_length = proxy.length delta = incoming_length - existing_length if delta > 0: target.add(delta) else: while delta < 0: target.pop() delta += 1 return if isinstance(target_rna, type(T.SplineBezierPoints.bl_rna)): existing_length = len(target) incoming_length = proxy.length delta = incoming_length - existing_length if delta > 0: target.add(delta) else: logger.error("Remove not implemented for type SplineBezierPoints") return logger.error( f"Not implemented fit_aos for type {target.bl_rna} for {target} ...")
def add_element(proxy: Proxy, collection: T.bpy_prop_collection, key: str): """Add an element to a bpy_prop_collection using the collection specific API """ bl_rna = getattr(collection, "bl_rna", None) if bl_rna is not None: if isinstance(bl_rna, type(T.KeyingSets.bl_rna)): idname = proxy.data("bl_idname") return collection.new(name=key, idname=idname) if isinstance(bl_rna, type(T.KeyingSetPaths.bl_rna)): # TODO current implementation fails # All keying sets paths have an empty name, and insertion with add()à failes # with an empty name target_ref = proxy.data("id") if target_ref is None: target = None else: target = target_ref.target() data_path = proxy.data("data_path") index = proxy.data("array_index") group_method = proxy.data("group_method") group_name = proxy.data("group") return collection.add(target_id=target, data_path=data_path, index=index, group_method=group_method, group_name=group_name) if isinstance(bl_rna, type(T.Nodes.bl_rna)): node_type = proxy.data("bl_idname") return collection.new(node_type) if isinstance(bl_rna, type(T.Sequences.bl_rna)): type_ = proxy.data("type") name = proxy.data("name") channel = proxy.data("channel") frame_start = proxy.data("frame_start") if type_ in effect_sequences: # overwritten anyway frame_end = frame_start + 1 return collection.new_effect(name, type_, channel, frame_start, frame_end=frame_end) if type_ == "SOUND": sound = proxy.data("sound") target = sound.target() if not target: logger.warning( f"missing target ID block for bpy.data.{sound.collection}[{sound.key}] " ) return None filepath = target.filepath return collection.new_sound(name, filepath, channel, frame_start) if type_ == "MOVIE": filepath = proxy.data("filepath") return collection.new_movie(name, filepath, channel, frame_start) if type_ == "IMAGE": directory = proxy.data("directory") filename = proxy.data("elements").data(0).data("filename") filepath = str(Path(directory) / filename) return collection.new_image(name, filepath, channel, frame_start) logger.warning(f"Sequence type not implemented: {type_}") # SCENE may be harder than it seems, since we cannot order scene creations. # Currently the creation order is the "deepmost" order as listed in proxy.py:_creation_order # but it does not work for this case return None if isinstance(bl_rna, type(T.SequenceModifiers.bl_rna)): name = proxy.data("name") type_ = proxy.data("type") return collection.new(name, type_) try: return collection.add() except Exception: pass # try our best new_or_add = getattr(collection, "new", None) if new_or_add is None: new_or_add = getattr(collection, "add", None) if new_or_add is None: logger.warning( f"Not implemented new or add for bpy.data.{collection}[{key}] ...") return None try: return new_or_add(key) except Exception: logger.warning( f"Not implemented new or add for type {type(collection)} for {collection}[{key}] ..." ) for s in traceback.format_exc().splitlines(): logger.warning(f"...{s}") return None
def _add_element_one(collection: T.bpy_prop_collection, proxy: Proxy, context: Context): return collection.add(1)
def _(collection: T.bpy_prop_collection, proxy: Proxy, index: int, context: Context) -> T.bpy_struct: return collection.add(1)