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:
authorInes Almeida <britalmeida@gmail.com>2016-02-26 22:50:29 +0300
committerInes Almeida <britalmeida@gmail.com>2016-03-03 04:08:21 +0300
commitd7cd2f6dfe8c424a11bdd6f0a9060ad985c851c7 (patch)
tree5240d3927b8cec175d85eac39b3414ca77a914a6 /bone_selection_sets.py
parentd33b3e15ca6672490062774d18965af3d4968cf0 (diff)
Refactored Selection Sets to have an interface similar to Bone Groups.
'Toggle' operator was converted into Select/Deselect, which adds and deletes from the selection, respectively. Added Assign/Unassign to be able to edit a set. Tweaked bl-info and properties descriptions and labels Motionpath functions from the Gooseberry branch were removed
Diffstat (limited to 'bone_selection_sets.py')
-rw-r--r--bone_selection_sets.py315
1 files changed, 315 insertions, 0 deletions
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()