Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bone_selection_groups.py244
-rw-r--r--bone_selection_sets.py315
2 files changed, 315 insertions, 244 deletions
diff --git a/bone_selection_groups.py b/bone_selection_groups.py
deleted file mode 100644
index 1c00bb13..00000000
--- a/bone_selection_groups.py
+++ /dev/null
@@ -1,244 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ***** END GPL LICENCE BLOCK *****
-
-bl_info = {
- "name": "Bone Selection Groups",
- "author": "Antony Riakiotakis",
- "version": (1, 0, 2),
- "blender": (2, 75, 0),
- "location": "Properties > Object Buttons",
- "description": "Operator and storage for restoration of bone selection state.",
- "category": "Animation",
-}
-
-import bpy
-from bpy.types import (
- Operator,
- Panel,
- UIList,
-)
-
-from bpy.props import (
- StringProperty,
- BoolProperty,
- IntProperty,
- FloatProperty,
- EnumProperty,
- CollectionProperty,
- BoolVectorProperty,
- FloatVectorProperty,
-)
-
-
-class POSE_PT_selection_sets(Panel):
- bl_label = "Selection Sets"
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "data"
-
- @classmethod
- def poll(cls, context):
- return context.object.type == 'ARMATURE'
-
- def draw(self, context):
- layout = self.layout
-
- armature = context.object
-
- # Rig type list
- row = layout.row()
- row.template_list(
- "POSE_UL_selection_set", "",
- armature, "selection_sets",
- armature, "active_selection_set")
-
- col = row.column()
- colsub = col.column(align=True)
- colsub.operator("pose.selection_set_add", icon='ZOOMIN', text="")
- colsub.operator("pose.selection_set_remove", icon='ZOOMOUT', text="")
-
- layout.operator("pose.selection_set_toggle")
-
-
-class POSE_UL_selection_set(UIList):
- def draw_item(self, context, layout, data, set, icon, active_data, active_propname, index):
- layout.prop(set, "name", text="", emboss=False)
-
-
-class SelectionEntry(bpy.types.PropertyGroup):
- name = StringProperty(name="Bone Name")
-
-
-class SelectionSet(bpy.types.PropertyGroup):
- name = StringProperty(name="Set Name")
- bone_ids = CollectionProperty(type=SelectionEntry)
-
-
-class PluginOperator(Operator):
- @classmethod
- def poll(self, context):
- return (context.object and
- context.object.type == 'ARMATURE' and
- context.mode == 'POSE')
-
-
-class POSE_OT_selection_set_add(PluginOperator):
- bl_idname = "pose.selection_set_add"
- bl_label = "Add Selection Set"
- bl_options = {'UNDO', 'REGISTER'}
-
- def execute(self, context):
- keep = False
- armature = context.object
- pose = armature.pose
-
- selection_set = armature.selection_sets.add()
- selection_set.name = "SelectionSet.%d" % len(armature.selection_sets)
- armature.active_selection_set = len(armature.selection_sets) - 1
- for bone in pose.bones:
- if (bone.bone.select):
- bone_id = selection_set.bone_ids.add()
- bone_id.name = bone.name
- keep = True
-
- if (not keep):
- armature.selection_sets.remove(armature.active_selection_set)
- numsets = len(armature.selection_sets)
- if (armature.active_selection_set > (numsets - 1) and numsets > 0):
- armature.active_selection_set = len(armature.selection_sets) - 1
- return {'CANCELLED'}
-
- return {'FINISHED'}
-
-
-class POSE_OT_selection_set_remove(PluginOperator):
- bl_idname = "pose.selection_set_remove"
- bl_label = "Delete Selection Set"
- bl_options = {'UNDO', 'REGISTER'}
-
- def execute(self, context):
- armature = context.object
-
- armature.selection_sets.remove(armature.active_selection_set)
- numsets = len(armature.selection_sets)
- if (armature.active_selection_set > (numsets - 1) and numsets > 0):
- armature.active_selection_set = len(armature.selection_sets) - 1
- return {'FINISHED'}
-
-
-class POSE_OT_selection_set_toggle(PluginOperator):
- bl_idname = "pose.selection_set_toggle"
- bl_label = "Toggle Selection Set"
- bl_options = {'UNDO', 'REGISTER'}
-
- def execute(self, context):
- armature = context.object
- pose = armature.pose
-
- selection_set = armature.selection_sets[armature.active_selection_set]
- for bone in pose.bones:
- bone.bone.select = False
-
- for bone in selection_set.bone_ids:
- pose.bones[bone.name].bone.select = True
-
- return {'FINISHED'}
-
-
-class MotionPathsCopyStartFrame(Operator):
- bl_idname = "anim.motionpaths_copy_scene_startframe"
- bl_label = "Copy Scene Start Frame"
- bl_options = {'REGISTER', 'UNDO'}
-
- armature_paths = BoolProperty()
-
- @classmethod
- def poll(cls, context):
- return (context.object)
-
- def execute(self, context):
- avs = None
- motionpath = None
- ob = context.object
- scene = context.scene
-
- if (self.armature_paths):
- avs = ob.pose.animation_visualization
- else:
- avs = ob.animation_visualization
-
- preview = scene.use_preview_range
-
- if (avs):
- motionpath = avs.motion_path
-
- if (motionpath):
- if (preview):
- motionpath.frame_start = scene.frame_preview_start
- motionpath.frame_end = scene.frame_preview_end
- else:
- motionpath.frame_start = scene.frame_start
- motionpath.frame_end = scene.frame_end
- else:
- return {'CANCELLED'}
-
- return {'FINISHED'}
-
-
-classes = (
- POSE_PT_selection_sets,
- POSE_UL_selection_set,
- SelectionEntry,
- SelectionSet,
- POSE_OT_selection_set_add,
- POSE_OT_selection_set_remove,
- POSE_OT_selection_set_toggle,
- MotionPathsCopyStartFrame
-)
-
-
-def copy_frames_armature(self, context):
- layout = self.layout
- layout.operator("anim.motionpaths_copy_scene_startframe").armature_paths = True
-
-
-def copy_frames_object(self, context):
- layout = self.layout
- layout.operator("anim.motionpaths_copy_scene_startframe").armature_paths = False
-
-
-def register():
- for cls in classes:
- bpy.utils.register_class(cls)
-
- bpy.types.Object.selection_sets = CollectionProperty(type=SelectionSet)
- bpy.types.Object.active_selection_set = IntProperty()
- bpy.types.DATA_PT_motion_paths.append(copy_frames_armature)
- bpy.types.OBJECT_PT_motion_paths.append(copy_frames_object)
-
-
-def unregister():
- for cls in classes:
- bpy.utils.unregister_class(cls)
-
- del bpy.types.Object.selection_sets
- del bpy.types.Object.active_selection_set
-
-
-if __name__ == "__main__":
- register()
diff --git a/bone_selection_sets.py b/bone_selection_sets.py
new file mode 100644
index 00000000..8bd4841e
--- /dev/null
+++ b/bone_selection_sets.py
@@ -0,0 +1,315 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+
+bl_info = {
+ "name": "Bone Selection Sets",
+ "author": "Antony Riakiotakis, InĂªs Almeida",
+ "version": (2, 0, 0),
+ "blender": (2, 75, 0),
+ "location": "Properties > Object Data (Armature) > Selection Sets",
+ "description": "List of Bone sets for easy selection while animating",
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
+ "Scripts/Animation/SelectionSets",
+ "category": "Animation",
+}
+
+import bpy
+from bpy.types import (
+ Operator,
+ Menu,
+ Panel,
+ UIList,
+ PropertyGroup,
+)
+
+from bpy.props import (
+ StringProperty,
+ BoolProperty,
+ IntProperty,
+ FloatProperty,
+ EnumProperty,
+ CollectionProperty,
+ BoolVectorProperty,
+ FloatVectorProperty,
+)
+
+# Data Structure ##############################################################
+
+# Note: bones are stored by name, this means that if the bone is renamed,
+# there can be problems. However, bone renaming is unlikely during animation
+class SelectionEntry(PropertyGroup):
+ name = StringProperty(name="Bone Name")
+
+
+class SelectionSet(PropertyGroup):
+ name = StringProperty(name="Set Name")
+ bone_ids = CollectionProperty(type=SelectionEntry)
+
+
+# UI Panel w/ UIList ##########################################################
+
+class POSE_MT_selection_sets_specials(Menu):
+ bl_label = "Selection Sets Specials"
+
+ def draw(self, context):
+ layout = self.layout
+
+ # TODO
+ #layout.operator("pose.selection_sets_sort", icon='SORTALPHA', text="Sort by Name").sort_type = 'NAME'
+
+
+class POSE_PT_selection_sets(Panel):
+ bl_label = "Selection Sets"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ return (context.armature
+ and context.object
+ and context.object.type == 'ARMATURE'
+ and context.object.pose
+ )
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+ arm = context.object
+
+ layout.enabled = (ob.proxy is None)
+
+ row = layout.row()
+
+ # UI list
+ rows = 4 #TODO if is being used, else 1
+ row.template_list(
+ "POSE_UL_selection_set", "",
+ arm, "selection_sets",
+ arm, "active_selection_set",
+ rows=rows
+ )
+
+ # add/remove/specials UI list Menu
+ col = row.column(align=True)
+ col.operator("pose.selection_set_add", icon='ZOOMIN', text="")
+ col.operator("pose.selection_set_remove", icon='ZOOMOUT', text="")
+ # TODO specials like sorting
+ #col.menu("POSE_MT_selection_sets_specials", icon='DOWNARROW_HLT', text="")
+
+ # TODO move up/down arrows
+
+ # buttons
+ row = layout.row()
+
+ sub = row.row(align=True)
+ sub.operator("pose.selection_set_assign", text="Assign")
+ sub.operator("pose.selection_set_unassign", text="Remove")
+
+ sub = row.row(align=True)
+ sub.operator("pose.selection_set_select", text="Select")
+ sub.operator("pose.selection_set_deselect", text="Deselect")
+
+
+class POSE_UL_selection_set(UIList):
+ def draw_item(self, context, layout, data, set, icon, active_data, active_propname, index):
+ layout.prop(set, "name", text="", emboss=False)
+
+
+# Operators ###################################################################
+
+class PluginOperator(Operator):
+ @classmethod
+ def poll(self, context):
+ return (context.object and
+ context.object.type == 'ARMATURE' and
+ context.mode == 'POSE')
+
+class NeedSelSetPluginOperator(PluginOperator):
+ @classmethod
+ def poll(self, context):
+ if super().poll(context):
+ arm = context.object
+ return (arm.active_selection_set < len(arm.selection_sets))
+ return False
+
+
+class POSE_OT_selection_set_add(PluginOperator):
+ bl_idname = "pose.selection_set_add"
+ bl_label = "Create Selection Set"
+ bl_description = "Creates a new empty Selection Set"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ created_counter = 0
+
+ def execute(self, context):
+ arm = context.object
+
+ selection_set = arm.selection_sets.add()
+
+ selection_set.name = "SelectionSet"
+ if POSE_OT_selection_set_add.created_counter > 0:
+ selection_set.name += ".{:03d}".format(POSE_OT_selection_set_add.created_counter)
+ POSE_OT_selection_set_add.created_counter += 1
+
+ arm.active_selection_set = len(arm.selection_sets) - 1
+
+ return {'FINISHED'}
+
+
+class POSE_OT_selection_set_remove(NeedSelSetPluginOperator):
+ bl_idname = "pose.selection_set_remove"
+ bl_label = "Delete Selection Set"
+ bl_description = "Delete a Selection Set"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ arm = context.object
+
+ arm.selection_sets.remove(arm.active_selection_set)
+ numsets = len(arm.selection_sets)
+ if (arm.active_selection_set > (numsets - 1) and numsets > 0):
+ arm.active_selection_set = len(arm.selection_sets) - 1
+ return {'FINISHED'}
+
+
+class POSE_OT_selection_set_assign(NeedSelSetPluginOperator):
+ bl_idname = "pose.selection_set_assign"
+ bl_label = "Add Bones to Selection Set"
+ bl_description = "Add selected bones to Selection Set"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ arm = context.object
+ pose = arm.pose
+
+ #if arm.active_selection_set <= 0:
+ # arm.selection_sets.add()
+ #TODO naming convention
+ # return {'FINISHED'}
+
+ selection_set = arm.selection_sets[arm.active_selection_set]
+ for bone in pose.bones:
+ if bone.bone.select:
+ bone_id = selection_set.bone_ids.add()
+ bone_id.name = bone.name
+
+ return {'FINISHED'}
+
+
+class POSE_OT_selection_set_unassign(NeedSelSetPluginOperator):
+ bl_idname = "pose.selection_set_unassign"
+ bl_label = "Remove Bones from Selection Set"
+ bl_description = "Remove selected bones from Selection Set"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ arm = context.object
+ pose = arm.pose
+
+ selection_set = arm.selection_sets[arm.active_selection_set]
+ for bone in pose.bones:
+ if bone.bone.select and bone.name in selection_set.bone_ids:
+ selection_set.bone_ids[bone.name].remove()
+
+ return {'FINISHED'}
+
+
+class POSE_OT_selection_set_select(NeedSelSetPluginOperator):
+ bl_idname = "pose.selection_set_select"
+ bl_label = "Select Selection Set"
+ bl_description = "Add Selection Set bones to current selection"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ arm = context.object
+ pose = arm.pose
+
+ selection_set = arm.selection_sets[arm.active_selection_set]
+ for bone in pose.bones:
+ if bone.name in selection_set.bone_ids:
+ bone.bone.select = True
+
+ return {'FINISHED'}
+
+
+class POSE_OT_selection_set_deselect(NeedSelSetPluginOperator):
+ bl_idname = "pose.selection_set_deselect"
+ bl_label = "Deselect Selection Set"
+ bl_description = "Remove Selection Set bones from current selection"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ arm = context.object
+ pose = arm.pose
+
+ selection_set = arm.selection_sets[arm.active_selection_set]
+ for bone in pose.bones:
+ if bone.name in selection_set.bone_ids:
+ bone.bone.select = False
+
+ return {'FINISHED'}
+
+
+# Registry ####################################################################
+
+classes = (
+ POSE_MT_selection_sets_specials,
+ POSE_PT_selection_sets,
+ POSE_UL_selection_set,
+ SelectionEntry,
+ SelectionSet,
+ POSE_OT_selection_set_add,
+ POSE_OT_selection_set_remove,
+ POSE_OT_selection_set_assign,
+ POSE_OT_selection_set_unassign,
+ POSE_OT_selection_set_select,
+ POSE_OT_selection_set_deselect,
+)
+
+def register():
+ for cls in classes:
+ bpy.utils.register_class(cls)
+
+ bpy.types.Object.selection_sets = CollectionProperty(
+ type=SelectionSet,
+ name="Selection Sets",
+ description="List of groups of bones for easy selection"
+ )
+ bpy.types.Object.active_selection_set = IntProperty(
+ name="Active Selection Set",
+ description="Index of the currently active selection set",
+ default=0
+ )
+
+ bpy.types.DATA_PT_motion_paths.append(copy_frames_armature)
+ bpy.types.OBJECT_PT_motion_paths.append(copy_frames_object)
+
+
+def unregister():
+ for cls in classes:
+ bpy.utils.unregister_class(cls)
+
+ del bpy.types.Object.selection_sets
+ del bpy.types.Object.active_selection_set
+
+
+if __name__ == "__main__":
+ register()