Skip to content
Snippets Groups Projects
Commit 9ae27536 authored by Demeter Dzadik's avatar Demeter Dzadik Committed by Demeter Dzadik
Browse files

Copy Attributes: Copy Custom Properties

This patch adds the functionality to copy custom properties from active to selected bones, or from active to selected objects.

Test file: {F11494335}

It is currently not possible to copy custom properties from a bone to an object or vice versa, which is consistent with the fact that it is not possible to do this with constraints. Maybe in future.

Reviewed By: bassamk, sybren

Differential Revision: https://developer.blender.org/D11299
parent ded03453
No related branches found
No related tags found
No related merge requests found
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
bl_info = { bl_info = {
"name": "Copy Attributes Menu", "name": "Copy Attributes Menu",
"author": "Bassam Kurdali, Fabian Fricke, Adam Wiseman", "author": "Bassam Kurdali, Fabian Fricke, Adam Wiseman, Demeter Dzadik",
"version": (0, 4, 9), "version": (0, 5, 0),
"blender": (2, 80, 0), "blender": (3, 0, 0),
"location": "View3D > Ctrl-C", "location": "View3D > Ctrl-C",
"description": "Copy Attributes Menu from Blender 2.4", "description": "Copy Attributes Menu",
"doc_url": "{BLENDER_MANUAL_URL}/addons/interface/copy_attributes.html", "doc_url": "{BLENDER_MANUAL_URL}/addons/interface/copy_attributes.html",
"category": "Interface", "category": "Interface",
} }
...@@ -248,6 +248,79 @@ def pose_invoke_func(self, context, event): ...@@ -248,6 +248,79 @@ def pose_invoke_func(self, context, event):
return {'RUNNING_MODAL'} return {'RUNNING_MODAL'}
CustomPropSelectionBoolsProperty = BoolVectorProperty(
size=32,
options={'SKIP_SAVE'}
)
class CopySelection:
"""Base class for copying properties from active to selected based on a selection."""
selection: CustomPropSelectionBoolsProperty
def draw_bools(self, button_names):
"""Draws the boolean toggle list with a list of strings for the button texts."""
layout = self.layout
for idx, name in enumerate(button_names):
layout.prop(self, "selection", index=idx, text=name,
toggle=True)
def copy_custom_property(source, destination, prop_name):
"""Copy a custom property called prop_name, from source to destination.
source and destination must be a Blender data type that can hold custom properties.
For a list of such data types, see:
https://docs.blender.org/manual/en/latest/files/data_blocks.html#files-data-blocks-custom-properties
"""
# Create the property.
destination[prop_name] = source[prop_name]
# Copy the settings of the property.
try:
dst_prop_manager = destination.id_properties_ui(prop_name)
except TypeError:
# Python values like lists or dictionaries don't have any settings to copy.
# They just consist of a value and nothing else.
return
src_prop_manager = source.id_properties_ui(prop_name)
assert src_prop_manager, f'Property "{prop_name}" not found in {source}'
dst_prop_manager.update_from(src_prop_manager)
# Copy the Library Overridable flag, which is stored elsewhere.
prop_rna_path = f'["{prop_name}"]'
is_lib_overridable = source.is_property_overridable_library(prop_rna_path)
destination.property_overridable_library_set(prop_rna_path, is_lib_overridable)
class CopyCustomProperties(CopySelection):
"""Base class for copying a selection of custom properties."""
def copy_selected_custom_props(self, active, selected):
keys = list(active.keys())
for item in selected:
if item == active:
continue
for index, is_selected in enumerate(self.selection):
if is_selected:
copy_custom_property(active, item, keys[index])
class CopySelectedBoneCustomProperties(CopyCustomProperties, Operator):
"""Copy Chosen custom properties from active to selected"""
bl_idname = "pose.copy_selected_custom_props"
bl_label = "Copy Selected Custom Properties"
bl_options = {'REGISTER', 'UNDO'}
poll = pose_poll_func
invoke = pose_invoke_func
def draw(self, context):
self.draw_bools(context.active_pose_bone.keys())
def execute(self, context):
self.copy_selected_custom_props(context.active_pose_bone, context.selected_pose_bones)
return {'FINISHED'}
class CopySelectedPoseConstraints(Operator): class CopySelectedPoseConstraints(Operator):
"""Copy Chosen constraints from active to selected""" """Copy Chosen constraints from active to selected"""
bl_idname = "pose.copy_selected_constraints" bl_idname = "pose.copy_selected_constraints"
...@@ -291,6 +364,7 @@ class VIEW3D_MT_posecopypopup(Menu): ...@@ -291,6 +364,7 @@ class VIEW3D_MT_posecopypopup(Menu):
for op in pose_copies: for op in pose_copies:
layout.operator("pose.copy_" + op[0]) layout.operator("pose.copy_" + op[0])
layout.operator("pose.copy_selected_constraints") layout.operator("pose.copy_selected_constraints")
layout.operator("pose.copy_selected_custom_props")
layout.operator("pose.copy", text="copy pose") layout.operator("pose.copy", text="copy pose")
...@@ -614,6 +688,22 @@ class CopySelectedObjectModifiers(Operator): ...@@ -614,6 +688,22 @@ class CopySelectedObjectModifiers(Operator):
return{'FINISHED'} return{'FINISHED'}
class CopySelectedObjectCustomProperties(CopyCustomProperties, Operator):
"""Copy Chosen custom properties from active to selected objects"""
bl_idname = "object.copy_selected_custom_props"
bl_label = "Copy Selected Custom Properties"
bl_options = {'REGISTER', 'UNDO'}
poll = object_poll_func
invoke = object_invoke_func
def draw(self, context):
self.draw_bools(context.object.keys())
def execute(self, context):
self.copy_selected_custom_props(context.object, context.selected_objects)
return {'FINISHED'}
object_ops = [] object_ops = []
genops(object_copies, object_ops, "object.copy_", object_poll_func, obLoopExec) genops(object_copies, object_ops, "object.copy_", object_poll_func, obLoopExec)
...@@ -638,6 +728,7 @@ class VIEW3D_MT_copypopup(Menu): ...@@ -638,6 +728,7 @@ class VIEW3D_MT_copypopup(Menu):
layout.operator("object.copy_" + op[0]) layout.operator("object.copy_" + op[0])
layout.operator("object.copy_selected_constraints") layout.operator("object.copy_selected_constraints")
layout.operator("object.copy_selected_modifiers") layout.operator("object.copy_selected_modifiers")
layout.operator("object.copy_selected_custom_props")
# Begin Mesh copy settings: # Begin Mesh copy settings:
...@@ -810,9 +901,11 @@ class MESH_OT_CopyFaceSettings(Operator): ...@@ -810,9 +901,11 @@ class MESH_OT_CopyFaceSettings(Operator):
classes = ( classes = (
CopySelectedPoseConstraints, CopySelectedPoseConstraints,
CopySelectedBoneCustomProperties,
VIEW3D_MT_posecopypopup, VIEW3D_MT_posecopypopup,
CopySelectedObjectConstraints, CopySelectedObjectConstraints,
CopySelectedObjectModifiers, CopySelectedObjectModifiers,
CopySelectedObjectCustomProperties,
VIEW3D_MT_copypopup, VIEW3D_MT_copypopup,
MESH_MT_CopyFaceSettings, MESH_MT_CopyFaceSettings,
MESH_MT_CopyUVCoordsFromLayer, MESH_MT_CopyUVCoordsFromLayer,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment