7aa1dee2721beecf6ab02ce075f49ae17391b269
[blender-staging.git] / release / scripts / startup / bl_ui / properties_data_armature.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 from rna_prop_ui import PropertyPanel
22
23 class ArmatureButtonsPanel():
24     bl_space_type = 'PROPERTIES'
25     bl_region_type = 'WINDOW'
26     bl_context = "data"
27
28     @classmethod
29     def poll(cls, context):
30         return context.armature
31
32
33 class DATA_PT_context_arm(ArmatureButtonsPanel, bpy.types.Panel):
34     bl_label = ""
35     bl_options = {'HIDE_HEADER'}
36
37     def draw(self, context):
38         layout = self.layout
39
40         ob = context.object
41         arm = context.armature
42         space = context.space_data
43
44         if ob:
45             layout.template_ID(ob, "data")
46         elif arm:
47             layout.template_ID(space, "pin_id")
48
49
50 class DATA_PT_skeleton(ArmatureButtonsPanel, bpy.types.Panel):
51     bl_label = "Skeleton"
52
53     def draw(self, context):
54         layout = self.layout
55
56         arm = context.armature
57
58         layout.prop(arm, "pose_position", expand=True)
59
60         col = layout.column()
61         col.label(text="Layers:")
62         col.prop(arm, "layers", text="")
63         col.label(text="Protected Layers:")
64         col.prop(arm, "layers_protected", text="")
65
66         layout.label(text="Deform:")
67         flow = layout.column_flow()
68         flow.prop(arm, "use_deform_vertex_groups", text="Vertex Groups")
69         flow.prop(arm, "use_deform_envelopes", text="Envelopes")
70         flow.prop(arm, "use_deform_preserve_volume", text="Quaternion")
71
72
73 class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel):
74     bl_label = "Display"
75
76     def draw(self, context):
77         layout = self.layout
78
79         ob = context.object
80         arm = context.armature
81
82         layout.prop(arm, "draw_type", expand=True)
83
84         split = layout.split()
85
86         col = split.column()
87         col.prop(arm, "show_names", text="Names")
88         col.prop(arm, "show_axes", text="Axes")
89         col.prop(arm, "show_bone_custom_shapes", text="Shapes")
90
91         col = split.column()
92         col.prop(arm, "show_group_colors", text="Colors")
93         if ob:
94             col.prop(ob, "show_x_ray", text="X-Ray")
95         col.prop(arm, "use_deform_delay", text="Delay Refresh")
96
97
98 class DATA_PT_bone_groups(ArmatureButtonsPanel, bpy.types.Panel):
99     bl_label = "Bone Groups"
100
101     @classmethod
102     def poll(cls, context):
103         return (context.object and context.object.type == 'ARMATURE' and context.object.pose)
104
105     def draw(self, context):
106         layout = self.layout
107
108         ob = context.object
109         pose = ob.pose
110
111         row = layout.row()
112         row.template_list(pose, "bone_groups", pose.bone_groups, "active_index", rows=2)
113
114         col = row.column(align=True)
115         col.active = (ob.proxy is None)
116         col.operator("pose.group_add", icon='ZOOMIN', text="")
117         col.operator("pose.group_remove", icon='ZOOMOUT', text="")
118
119         group = pose.bone_groups.active
120         if group:
121             col = layout.column()
122             col.active = (ob.proxy is None)
123             col.prop(group, "name")
124
125             split = layout.split()
126             split.active = (ob.proxy is None)
127
128             col = split.column()
129             col.prop(group, "color_set")
130             if group.color_set:
131                 col = split.column()
132                 sub = col.row(align=True)
133                 sub.prop(group.colors, "normal", text="")
134                 sub.prop(group.colors, "select", text="")
135                 sub.prop(group.colors, "active", text="")
136
137         row = layout.row()
138         row.active = (ob.proxy is None)
139
140         sub = row.row(align=True)
141         sub.operator("pose.group_assign", text="Assign")
142         sub.operator("pose.group_unassign", text="Remove")  # row.operator("pose.bone_group_remove_from", text="Remove")
143
144         sub = row.row(align=True)
145         sub.operator("pose.group_select", text="Select")
146         sub.operator("pose.group_deselect", text="Deselect")
147
148
149 class DATA_PT_pose_library(ArmatureButtonsPanel, bpy.types.Panel):
150     bl_label = "Pose Library"
151     bl_options = {'DEFAULT_CLOSED'}
152
153     @classmethod
154     def poll(cls, context):
155         return (context.object and context.object.type == 'ARMATURE' and context.object.pose)
156
157     def draw(self, context):
158         layout = self.layout
159
160         ob = context.object
161         poselib = ob.pose_library
162
163         layout.template_ID(ob, "pose_library", new="poselib.new", unlink="poselib.unlink")
164
165         if poselib:
166             row = layout.row()
167             row.template_list(poselib, "pose_markers", poselib.pose_markers, "active_index", rows=5)
168
169             col = row.column(align=True)
170             col.active = (poselib.library is None)
171
172             # invoke should still be used for 'add', as it is needed to allow
173             # add/replace options to be used properly
174             col.operator("poselib.pose_add", icon='ZOOMIN', text="")
175
176             col.operator_context = 'EXEC_DEFAULT'  # exec not invoke, so that menu doesn't need showing
177
178             pose_marker_active = poselib.pose_markers.active
179
180             if pose_marker_active is not None:
181                 col.operator("poselib.pose_remove", icon='ZOOMOUT', text="").pose = pose_marker_active.name
182                 col.operator("poselib.apply_pose", icon='ZOOM_SELECTED', text="").pose_index = poselib.pose_markers.active_index
183
184             layout.operator("poselib.action_sanitise")
185
186
187 # TODO: this panel will soon be depreceated too
188 class DATA_PT_ghost(ArmatureButtonsPanel, bpy.types.Panel):
189     bl_label = "Ghost"
190
191     def draw(self, context):
192         layout = self.layout
193
194         arm = context.armature
195
196         layout.prop(arm, "ghost_type", expand=True)
197
198         split = layout.split()
199
200         col = split.column(align=True)
201
202         if arm.ghost_type == 'RANGE':
203             col.prop(arm, "ghost_frame_start", text="Start")
204             col.prop(arm, "ghost_frame_end", text="End")
205             col.prop(arm, "ghost_size", text="Step")
206         elif arm.ghost_type == 'CURRENT_FRAME':
207             col.prop(arm, "ghost_step", text="Range")
208             col.prop(arm, "ghost_size", text="Step")
209
210         col = split.column()
211         col.label(text="Display:")
212         col.prop(arm, "show_only_ghost_selected", text="Selected Only")
213
214
215 class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, bpy.types.Panel):
216     bl_label = "iTaSC parameters"
217     bl_options = {'DEFAULT_CLOSED'}
218
219     @classmethod
220     def poll(cls, context):
221         ob = context.object
222         return (ob and ob.pose)
223
224     def draw(self, context):
225         layout = self.layout
226
227         ob = context.object
228         itasc = ob.pose.ik_param
229
230         layout.prop(ob.pose, "ik_solver")
231
232         if itasc:
233             layout.prop(itasc, "mode", expand=True)
234             simulation = (itasc.mode == 'SIMULATION')
235             if simulation:
236                 layout.label(text="Reiteration:")
237                 layout.prop(itasc, "reiteration_method", expand=True)
238
239             row = layout.row()
240             row.active = not simulation or itasc.reiteration_method != 'NEVER'
241             row.prop(itasc, "precision")
242             row.prop(itasc, "iterations")
243
244             if simulation:
245                 layout.prop(itasc, "use_auto_step")
246                 row = layout.row()
247                 if itasc.use_auto_step:
248                     row.prop(itasc, "step_min", text="Min")
249                     row.prop(itasc, "step_max", text="Max")
250                 else:
251                     row.prop(itasc, "step_count")
252
253             layout.prop(itasc, "solver")
254             if simulation:
255                 layout.prop(itasc, "feedback")
256                 layout.prop(itasc, "velocity_max")
257             if itasc.solver == 'DLS':
258                 row = layout.row()
259                 row.prop(itasc, "damping_max", text="Damp", slider=True)
260                 row.prop(itasc, "damping_epsilon", text="Eps", slider=True)
261
262 from bl_ui.properties_animviz import (
263     MotionPathButtonsPanel,
264     OnionSkinButtonsPanel,
265     )
266
267 class DATA_PT_motion_paths(MotionPathButtonsPanel, bpy.types.Panel):
268     #bl_label = "Bones Motion Paths"
269     bl_context = "data"
270
271     @classmethod
272     def poll(cls, context):
273         # XXX: include posemode check?
274         return (context.object) and (context.armature)
275
276     def draw(self, context):
277         layout = self.layout
278
279         ob = context.object
280
281         self.draw_settings(context, ob.pose.animation_visualisation, bones=True)
282
283         layout.separator()
284
285         split = layout.split()
286         split.operator("pose.paths_calculate", text="Calculate Paths")
287         split.operator("pose.paths_clear", text="Clear Paths")
288
289
290 class DATA_PT_onion_skinning(OnionSkinButtonsPanel):  # , bpy.types.Panel): # inherit from panel when ready
291     #bl_label = "Bones Onion Skinning"
292     bl_context = "data"
293
294     @classmethod
295     def poll(cls, context):
296         # XXX: include posemode check?
297         return (context.object) and (context.armature)
298
299     def draw(self, context):
300         layout = self.layout
301
302         ob = context.object
303
304         self.draw_settings(context, ob.pose.animation_visualisation, bones=True)
305
306
307 class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, bpy.types.Panel):
308     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
309     _context_path = "object.data"
310     _property_type = bpy.types.Armature