4c0f8a3e52c97c6ced8fa170f9140f5b49a28bd7
[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_show_header = False
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 not bone:
60             bone = context.edit_bone
61             row = layout.row()
62             row.column().prop(bone, "head")
63             row.column().prop(bone, "tail")
64
65             col = row.column()
66             sub = col.column(align=True)
67             sub.label(text="Roll:")
68             sub.prop(bone, "roll", text="")
69             sub.label()
70             sub.prop(bone, "lock")
71
72         else:
73             pchan = ob.pose.bones[context.bone.name]
74
75             row = layout.row()
76             col = row.column()
77             col.prop(pchan, "location")
78             col.active = not (bone.parent and bone.use_connect)
79
80             col = row.column()
81             if pchan.rotation_mode == 'QUATERNION':
82                 col.prop(pchan, "rotation_quaternion", text="Rotation")
83             elif pchan.rotation_mode == 'AXIS_ANGLE':
84                 #col.label(text="Rotation")
85                 #col.prop(pchan, "rotation_angle", text="Angle")
86                 #col.prop(pchan, "rotation_axis", text="Axis")
87                 col.prop(pchan, "rotation_axis_angle", text="Rotation")
88             else:
89                 col.prop(pchan, "rotation_euler", text="Rotation")
90
91             row.column().prop(pchan, "scale")
92
93             layout.prop(pchan, "rotation_mode")
94
95
96 class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel):
97     bl_label = "Transform Locks"
98     bl_default_closed = True
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[context.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 not bone:
139             bone = context.edit_bone
140             pchan = None
141         else:
142             pchan = ob.pose.bones[context.bone.name]
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_object(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_object(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_hinge", 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         layout = self.layout
182
183         ob = context.object
184         bone = context.bone
185
186         if not bone:
187             bone = context.edit_bone
188             pchan = None
189         else:
190             pchan = ob.pose.bones[context.bone.name]
191
192         if ob and pchan:
193
194             split = layout.split()
195
196             col = split.column()
197             col.prop(bone, "show_wire", text="Wireframe")
198             col.prop(bone, "hide", text="Hide")
199
200             col = split.column()
201
202             col.label(text="Custom Shape:")
203             col.prop(pchan, "custom_shape", text="")
204             if pchan.custom_shape:
205                 col.prop_object(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
206
207
208 class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel):
209     bl_label = "Inverse Kinematics"
210     bl_default_closed = True
211
212     @classmethod
213     def poll(cls, context):
214         return context.active_pose_bone
215
216     def draw(self, context):
217         layout = self.layout
218
219         ob = context.object
220         bone = context.bone
221         pchan = ob.pose.bones[bone.name]
222
223         row = layout.row()
224         row.prop(ob.pose, "ik_solver")
225
226         split = layout.split(percentage=0.25)
227         split.prop(pchan, "lock_ik_x", text="Lock X")
228         split.active = pchan.is_in_ik_chain
229         row = split.row()
230         row.prop(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
231         row.active = pchan.lock_ik_x == False and pchan.is_in_ik_chain
232
233         split = layout.split(percentage=0.25)
234         sub = split.row()
235
236         sub.prop(pchan, "ik_limit_x", text="Limit")
237         sub.active = pchan.lock_ik_x == False and pchan.is_in_ik_chain
238         sub = split.row(align=True)
239         sub.prop(pchan, "ik_min_x", text="")
240         sub.prop(pchan, "ik_max_x", text="")
241         sub.active = pchan.lock_ik_x == False and pchan.ik_limit_x and pchan.is_in_ik_chain
242
243         split = layout.split(percentage=0.25)
244         split.prop(pchan, "lock_ik_y", text="Y")
245         split.active = pchan.is_in_ik_chain and pchan.is_in_ik_chain
246         row = split.row()
247         row.prop(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
248         row.active = pchan.lock_ik_y == False and pchan.is_in_ik_chain
249
250         split = layout.split(percentage=0.25)
251         sub = split.row()
252
253         sub.prop(pchan, "ik_limit_y", text="Limit")
254         sub.active = pchan.lock_ik_y == False and pchan.is_in_ik_chain
255
256         sub = split.row(align=True)
257         sub.prop(pchan, "ik_min_y", text="")
258         sub.prop(pchan, "ik_max_y", text="")
259         sub.active = pchan.lock_ik_y == False and pchan.ik_limit_y and pchan.is_in_ik_chain
260
261         split = layout.split(percentage=0.25)
262         split.prop(pchan, "lock_ik_z", text="Z")
263         split.active = pchan.is_in_ik_chain and pchan.is_in_ik_chain
264         sub = split.row()
265         sub.prop(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
266         sub.active = pchan.lock_ik_z == False and pchan.is_in_ik_chain
267
268         split = layout.split(percentage=0.25)
269         sub = split.row()
270
271         sub.prop(pchan, "ik_limit_z", text="Limit")
272         sub.active = pchan.lock_ik_z == False and pchan.is_in_ik_chain
273         sub = split.row(align=True)
274         sub.prop(pchan, "ik_min_z", text="")
275         sub.prop(pchan, "ik_max_z", text="")
276         sub.active = pchan.lock_ik_z == False and pchan.ik_limit_z and pchan.is_in_ik_chain
277         split = layout.split()
278         split.prop(pchan, "ik_stretch", text="Stretch", slider=True)
279         split.label()
280         split.active = pchan.is_in_ik_chain
281
282         if ob.pose.ik_solver == 'ITASC':
283             split = layout.split()
284             col = split.column()
285             col.prop(pchan, "ik_rot_control", text="Control Rotation")
286             col.active = pchan.is_in_ik_chain
287             col = split.column()
288             col.prop(pchan, "ik_rot_weight", text="Weight", slider=True)
289             col.active = pchan.is_in_ik_chain
290             # not supported yet
291             #row = layout.row()
292             #row.prop(pchan, "ik_lin_control", text="Joint Size")
293             #row.prop(pchan, "ik_lin_weight", text="Weight", slider=True)
294
295
296 class BONE_PT_deform(BoneButtonsPanel, bpy.types.Panel):
297     bl_label = "Deform"
298     bl_default_closed = True
299
300     def draw_header(self, context):
301         bone = context.bone
302
303         if not bone:
304             bone = context.edit_bone
305
306         self.layout.prop(bone, "use_deform", text="")
307
308     def draw(self, context):
309         layout = self.layout
310
311         bone = context.bone
312
313         if not bone:
314             bone = context.edit_bone
315
316         layout.active = bone.use_deform
317
318         split = layout.split()
319
320         col = split.column()
321         col.label(text="Envelope:")
322
323         sub = col.column(align=True)
324         sub.prop(bone, "envelope_distance", text="Distance")
325         sub.prop(bone, "envelope_weight", text="Weight")
326         col.prop(bone, "use_envelope_multiply", text="Multiply")
327
328         sub = col.column(align=True)
329         sub.label(text="Radius:")
330         sub.prop(bone, "head_radius", text="Head")
331         sub.prop(bone, "tail_radius", text="Tail")
332
333         col = split.column()
334         col.label(text="Curved Bones:")
335
336         sub = col.column(align=True)
337         sub.prop(bone, "bbone_segments", text="Segments")
338         sub.prop(bone, "bbone_in", text="Ease In")
339         sub.prop(bone, "bbone_out", text="Ease Out")
340
341         col.label(text="Offset:")
342         col.prop(bone, "use_cyclic_offset")
343
344
345 class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, bpy.types.Panel):
346     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
347
348     @property
349     def _context_path(self):
350         obj = bpy.context.object
351         if obj and obj.mode == 'POSE':
352             return "active_pose_bone"
353         else:
354             return "active_bone"
355
356
357 def register():
358     pass
359
360
361 def unregister():
362     pass
363
364 if __name__ == "__main__":
365     register()