minor changes to bone UI script.
[blender-staging.git] / release / scripts / ui / properties_data_bone.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
24 class BoneButtonsPanel():
25     bl_space_type = 'PROPERTIES'
26     bl_region_type = 'WINDOW'
27     bl_context = "bone"
28
29     @classmethod
30     def poll(cls, context):
31         return (context.bone or context.edit_bone)
32
33
34 class BONE_PT_context_bone(BoneButtonsPanel, bpy.types.Panel):
35     bl_label = ""
36     bl_options = {'HIDE_HEADER'}
37
38     def draw(self, context):
39         layout = self.layout
40
41         bone = context.bone
42         if not bone:
43             bone = context.edit_bone
44
45         row = layout.row()
46         row.label(text="", icon='BONE_DATA')
47         row.prop(bone, "name", text="")
48
49
50 class BONE_PT_transform(BoneButtonsPanel, bpy.types.Panel):
51     bl_label = "Transform"
52
53     def draw(self, context):
54         layout = self.layout
55
56         ob = context.object
57         bone = context.bone
58
59         if bone:
60             pchan = ob.pose.bones[bone.name]
61
62             row = layout.row()
63             col = row.column()
64             col.prop(pchan, "location")
65             col.active = not (bone.parent and bone.use_connect)
66
67             col = row.column()
68             if pchan.rotation_mode == 'QUATERNION':
69                 col.prop(pchan, "rotation_quaternion", text="Rotation")
70             elif pchan.rotation_mode == 'AXIS_ANGLE':
71                 #col.label(text="Rotation")
72                 #col.prop(pchan, "rotation_angle", text="Angle")
73                 #col.prop(pchan, "rotation_axis", text="Axis")
74                 col.prop(pchan, "rotation_axis_angle", text="Rotation")
75             else:
76                 col.prop(pchan, "rotation_euler", text="Rotation")
77
78             row.column().prop(pchan, "scale")
79
80             layout.prop(pchan, "rotation_mode")
81
82         else:
83             bone = context.edit_bone
84             row = layout.row()
85             row.column().prop(bone, "head")
86             row.column().prop(bone, "tail")
87
88             col = row.column()
89             sub = col.column(align=True)
90             sub.label(text="Roll:")
91             sub.prop(bone, "roll", text="")
92             sub.label()
93             sub.prop(bone, "lock")
94
95
96 class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel):
97     bl_label = "Transform Locks"
98     bl_options = {'DEFAULT_CLOSED'}
99
100     @classmethod
101     def poll(cls, context):
102         return context.bone
103
104     def draw(self, context):
105         layout = self.layout
106
107         ob = context.object
108         bone = context.bone
109         pchan = ob.pose.bones[bone.name]
110
111         row = layout.row()
112         col = row.column()
113         col.prop(pchan, "lock_location")
114         col.active = not (bone.parent and bone.use_connect)
115
116         col = row.column()
117         if pchan.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
118             col.prop(pchan, "lock_rotations_4d", text="Lock Rotation")
119             if pchan.lock_rotations_4d:
120                 col.prop(pchan, "lock_rotation_w", text="W")
121             col.prop(pchan, "lock_rotation", text="")
122         else:
123             col.prop(pchan, "lock_rotation", text="Rotation")
124
125         row.column().prop(pchan, "lock_scale")
126
127
128 class BONE_PT_relations(BoneButtonsPanel, bpy.types.Panel):
129     bl_label = "Relations"
130
131     def draw(self, context):
132         layout = self.layout
133
134         ob = context.object
135         bone = context.bone
136         arm = context.armature
137
138         if bone:
139             pchan = ob.pose.bones[bone.name]
140         else:
141             bone = context.edit_bone
142             pchan = None
143
144         split = layout.split()
145
146         col = split.column()
147         col.label(text="Layers:")
148         col.prop(bone, "layers", text="")
149
150         col.separator()
151
152         if ob and pchan:
153             col.label(text="Bone Group:")
154             col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="")
155
156         col = split.column()
157         col.label(text="Parent:")
158         if context.bone:
159             col.prop(bone, "parent", text="")
160         else:
161             col.prop_search(bone, "parent", arm, "edit_bones", text="")
162
163         sub = col.column()
164         sub.active = (bone.parent is not None)
165         sub.prop(bone, "use_connect")
166         sub.prop(bone, "use_inherit_rotation", text="Inherit Rotation")
167         sub.prop(bone, "use_inherit_scale", text="Inherit Scale")
168         sub = col.column()
169         sub.active = (not bone.parent or not bone.use_connect)
170         sub.prop(bone, "use_local_location", text="Local Location")
171
172
173 class BONE_PT_display(BoneButtonsPanel, bpy.types.Panel):
174     bl_label = "Display"
175
176     @classmethod
177     def poll(cls, context):
178         return context.bone
179
180     def draw(self, context):
181         # note. this works ok in editmode but isnt
182         # all that useful so disabling for now.
183         layout = self.layout
184
185         ob = context.object
186         bone = context.bone
187
188         if bone:
189             pchan = ob.pose.bones[bone.name]
190         else:
191             bone = context.edit_bone
192             pchan = None
193
194         if bone:
195             split = layout.split()
196
197             col = split.column()
198             col.prop(bone, "show_wire", text="Wireframe")
199             col.prop(bone, "hide", text="Hide")
200
201             if pchan:
202                 col = split.column()
203
204                 col.label(text="Custom Shape:")
205                 col.prop(pchan, "custom_shape", text="")
206                 if pchan.custom_shape:
207                     col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
208
209
210 class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel):
211     bl_label = "Inverse Kinematics"
212     bl_options = {'DEFAULT_CLOSED'}
213
214     @classmethod
215     def poll(cls, context):
216         return context.active_pose_bone
217
218     def draw(self, context):
219         layout = self.layout
220
221         pchan = context.active_pose_bone
222         # incase pose bone context is pinned don't use 'context.object'
223         ob = pchan.id_data
224
225         row = layout.row()
226         row.prop(ob.pose, "ik_solver")
227
228         split = layout.split(percentage=0.25)
229         split.prop(pchan, "lock_ik_x", icon='LOCKED' if pchan.lock_ik_x else 'UNLOCKED', text="X")
230         split.active = pchan.is_in_ik_chain
231         row = split.row()
232         row.prop(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
233         row.active = pchan.lock_ik_x == False and pchan.is_in_ik_chain
234
235         split = layout.split(percentage=0.25)
236         sub = split.row()
237
238         sub.prop(pchan, "use_ik_limit_x", text="Limit")
239         sub.active = pchan.lock_ik_x == False and pchan.is_in_ik_chain
240         sub = split.row(align=True)
241         sub.prop(pchan, "ik_min_x", text="")
242         sub.prop(pchan, "ik_max_x", text="")
243         sub.active = pchan.lock_ik_x == False and pchan.use_ik_limit_x and pchan.is_in_ik_chain
244
245         split = layout.split(percentage=0.25)
246         split.prop(pchan, "lock_ik_y", icon='LOCKED' if pchan.lock_ik_y else 'UNLOCKED', text="Y")
247         split.active = pchan.is_in_ik_chain
248         row = split.row()
249         row.prop(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
250         row.active = pchan.lock_ik_y == False and pchan.is_in_ik_chain
251
252         split = layout.split(percentage=0.25)
253         sub = split.row()
254
255         sub.prop(pchan, "use_ik_limit_y", text="Limit")
256         sub.active = pchan.lock_ik_y == False and pchan.is_in_ik_chain
257
258         sub = split.row(align=True)
259         sub.prop(pchan, "ik_min_y", text="")
260         sub.prop(pchan, "ik_max_y", text="")
261         sub.active = pchan.lock_ik_y == False and pchan.use_ik_limit_y and pchan.is_in_ik_chain
262
263         split = layout.split(percentage=0.25)
264         split.prop(pchan, "lock_ik_z", icon='LOCKED' if pchan.lock_ik_z else 'UNLOCKED', text="Z")
265         split.active = pchan.is_in_ik_chain
266         sub = split.row()
267         sub.prop(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
268         sub.active = pchan.lock_ik_z == False and pchan.is_in_ik_chain
269
270         split = layout.split(percentage=0.25)
271         sub = split.row()
272
273         sub.prop(pchan, "use_ik_limit_z", text="Limit")
274         sub.active = pchan.lock_ik_z == False and pchan.is_in_ik_chain
275         sub = split.row(align=True)
276         sub.prop(pchan, "ik_min_z", text="")
277         sub.prop(pchan, "ik_max_z", text="")
278         sub.active = pchan.lock_ik_z == False and pchan.use_ik_limit_z and pchan.is_in_ik_chain
279
280         split = layout.split(percentage=0.25)
281         split.label(text="Stretch:")
282         sub = split.row()
283         sub.prop(pchan, "ik_stretch", text="", slider=True)
284         sub.active = pchan.is_in_ik_chain
285
286         if ob.pose.ik_solver == 'ITASC':
287             split = layout.split()
288             col = split.column()
289             col.prop(pchan, "use_ik_rotation_control", text="Control Rotation")
290             col.active = pchan.is_in_ik_chain
291             col = split.column()
292             col.prop(pchan, "ik_rotation_weight", text="Weight", slider=True)
293             col.active = pchan.is_in_ik_chain
294             # not supported yet
295             #row = layout.row()
296             #row.prop(pchan, "use_ik_linear_control", text="Joint Size")
297             #row.prop(pchan, "ik_linear_weight", text="Weight", slider=True)
298
299
300 class BONE_PT_deform(BoneButtonsPanel, bpy.types.Panel):
301     bl_label = "Deform"
302     bl_options = {'DEFAULT_CLOSED'}
303
304     def draw_header(self, context):
305         bone = context.bone
306
307         if not bone:
308             bone = context.edit_bone
309
310         self.layout.prop(bone, "use_deform", text="")
311
312     def draw(self, context):
313         layout = self.layout
314
315         bone = context.bone
316
317         if not bone:
318             bone = context.edit_bone
319
320         layout.active = bone.use_deform
321
322         split = layout.split()
323
324         col = split.column()
325         col.label(text="Envelope:")
326
327         sub = col.column(align=True)
328         sub.prop(bone, "envelope_distance", text="Distance")
329         sub.prop(bone, "envelope_weight", text="Weight")
330         col.prop(bone, "use_envelope_multiply", text="Multiply")
331
332         sub = col.column(align=True)
333         sub.label(text="Radius:")
334         sub.prop(bone, "head_radius", text="Head")
335         sub.prop(bone, "tail_radius", text="Tail")
336
337         col = split.column()
338         col.label(text="Curved Bones:")
339
340         sub = col.column(align=True)
341         sub.prop(bone, "bbone_segments", text="Segments")
342         sub.prop(bone, "bbone_in", text="Ease In")
343         sub.prop(bone, "bbone_out", text="Ease Out")
344
345         col.label(text="Offset:")
346         col.prop(bone, "use_cyclic_offset")
347
348
349 class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, bpy.types.Panel):
350     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
351
352     @property
353     def _context_path(self):
354         obj = bpy.context.object
355         if obj and obj.mode == 'POSE':
356             return "active_pose_bone"
357         else:
358             return "active_bone"
359
360
361 def register():
362     pass
363
364
365 def unregister():
366     pass
367
368 if __name__ == "__main__":
369     register()