poll() as a python '@staticmethod' was too limiting and didnt allow useful base class...
[blender.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_custom_props(BoneButtonsPanel, PropertyPanel, bpy.types.Panel):
51     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
52
53     @property
54     def _context_path(self):
55         obj = bpy.context.object
56         if obj and obj.mode == 'POSE':
57             return "active_pose_bone"
58         else:
59             return "active_bone"
60
61
62 class BONE_PT_transform(BoneButtonsPanel, bpy.types.Panel):
63     bl_label = "Transform"
64
65     def draw(self, context):
66         layout = self.layout
67
68         ob = context.object
69         bone = context.bone
70
71         if not bone:
72             bone = context.edit_bone
73             row = layout.row()
74             row.column().prop(bone, "head")
75             row.column().prop(bone, "tail")
76
77             col = row.column()
78             sub = col.column(align=True)
79             sub.label(text="Roll:")
80             sub.prop(bone, "roll", text="")
81             sub.label()
82             sub.prop(bone, "lock")
83
84         else:
85             pchan = ob.pose.bones[context.bone.name]
86
87             row = layout.row()
88             col = row.column()
89             col.prop(pchan, "location")
90             col.active = not (bone.parent and bone.connected)
91
92             col = row.column()
93             if pchan.rotation_mode == 'QUATERNION':
94                 col.prop(pchan, "rotation_quaternion", text="Rotation")
95             elif pchan.rotation_mode == 'AXIS_ANGLE':
96                 #col.label(text="Rotation")
97                 #col.prop(pchan, "rotation_angle", text="Angle")
98                 #col.prop(pchan, "rotation_axis", text="Axis")
99                 col.prop(pchan, "rotation_axis_angle", text="Rotation")
100             else:
101                 col.prop(pchan, "rotation_euler", text="Rotation")
102
103             row.column().prop(pchan, "scale")
104
105             layout.prop(pchan, "rotation_mode")
106
107
108 class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel):
109     bl_label = "Transform Locks"
110     bl_default_closed = True
111
112     @classmethod
113     def poll(cls, context):
114         return context.bone
115
116     def draw(self, context):
117         layout = self.layout
118
119         ob = context.object
120         bone = context.bone
121         pchan = ob.pose.bones[context.bone.name]
122
123         row = layout.row()
124         col = row.column()
125         col.prop(pchan, "lock_location")
126         col.active = not (bone.parent and bone.connected)
127
128         col = row.column()
129         if pchan.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
130             col.prop(pchan, "lock_rotations_4d", text="Lock Rotation")
131             if pchan.lock_rotations_4d:
132                 col.prop(pchan, "lock_rotation_w", text="W")
133             col.prop(pchan, "lock_rotation", text="")
134         else:
135             col.prop(pchan, "lock_rotation", text="Rotation")
136
137         row.column().prop(pchan, "lock_scale")
138
139
140 class BONE_PT_relations(BoneButtonsPanel, bpy.types.Panel):
141     bl_label = "Relations"
142
143     def draw(self, context):
144         layout = self.layout
145
146         ob = context.object
147         bone = context.bone
148         arm = context.armature
149
150         if not bone:
151             bone = context.edit_bone
152             pchan = None
153         else:
154             pchan = ob.pose.bones[context.bone.name]
155
156         split = layout.split()
157
158         col = split.column()
159         col.label(text="Layers:")
160         col.prop(bone, "layer", text="")
161
162         col.separator()
163
164         if ob and pchan:
165             col.label(text="Bone Group:")
166             col.prop_object(pchan, "bone_group", ob.pose, "bone_groups", text="")
167
168         col = split.column()
169         col.label(text="Parent:")
170         if context.bone:
171             col.prop(bone, "parent", text="")
172         else:
173             col.prop_object(bone, "parent", arm, "edit_bones", text="")
174
175         sub = col.column()
176         sub.active = (bone.parent is not None)
177         sub.prop(bone, "connected")
178         sub.prop(bone, "hinge", text="Inherit Rotation")
179         sub.prop(bone, "inherit_scale", text="Inherit Scale")
180         sub = col.column()
181         sub.active = (not bone.parent or not bone.connected)
182         sub.prop(bone, "local_location", text="Local Location")
183
184
185 class BONE_PT_display(BoneButtonsPanel, bpy.types.Panel):
186     bl_label = "Display"
187
188     @classmethod
189     def poll(cls, context):
190         return context.bone
191
192     def draw(self, context):
193         layout = self.layout
194
195         ob = context.object
196         bone = context.bone
197
198         if not bone:
199             bone = context.edit_bone
200             pchan = None
201         else:
202             pchan = ob.pose.bones[context.bone.name]
203
204         if ob and pchan:
205
206             split = layout.split()
207
208             col = split.column()
209             col.prop(bone, "draw_wire", text="Wireframe")
210             col.prop(bone, "hide", text="Hide")
211
212             col = split.column()
213
214             col.label(text="Custom Shape:")
215             col.prop(pchan, "custom_shape", text="")
216             if pchan.custom_shape:
217                 col.prop_object(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
218
219
220 class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel):
221     bl_label = "Inverse Kinematics"
222     bl_default_closed = True
223
224     @classmethod
225     def poll(cls, context):
226         return context.active_pose_bone
227
228     def draw(self, context):
229         layout = self.layout
230
231         ob = context.object
232         bone = context.bone
233         pchan = ob.pose.bones[bone.name]
234
235         row = layout.row()
236         row.prop(ob.pose, "ik_solver")
237
238         split = layout.split(percentage=0.25)
239         split.prop(pchan, "ik_dof_x", text="X")
240         split.active = pchan.has_ik
241         row = split.row()
242         row.prop(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
243         row.active = pchan.ik_dof_x and pchan.has_ik
244
245         split = layout.split(percentage=0.25)
246         sub = split.row()
247
248         sub.prop(pchan, "ik_limit_x", text="Limit")
249         sub.active = pchan.ik_dof_x and pchan.has_ik
250         sub = split.row(align=True)
251         sub.prop(pchan, "ik_min_x", text="")
252         sub.prop(pchan, "ik_max_x", text="")
253         sub.active = pchan.ik_dof_x and pchan.ik_limit_x and pchan.has_ik
254
255         split = layout.split(percentage=0.25)
256         split.prop(pchan, "ik_dof_y", text="Y")
257         split.active = pchan.has_ik and pchan.has_ik
258         row = split.row()
259         row.prop(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
260         row.active = pchan.ik_dof_y and pchan.has_ik
261
262         split = layout.split(percentage=0.25)
263         sub = split.row()
264
265         sub.prop(pchan, "ik_limit_y", text="Limit")
266         sub.active = pchan.ik_dof_y and pchan.has_ik
267
268         sub = split.row(align=True)
269         sub.prop(pchan, "ik_min_y", text="")
270         sub.prop(pchan, "ik_max_y", text="")
271         sub.active = pchan.ik_dof_y and pchan.ik_limit_y and pchan.has_ik
272
273         split = layout.split(percentage=0.25)
274         split.prop(pchan, "ik_dof_z", text="Z")
275         split.active = pchan.has_ik and pchan.has_ik
276         sub = split.row()
277         sub.prop(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
278         sub.active = pchan.ik_dof_z and pchan.has_ik
279
280         split = layout.split(percentage=0.25)
281         sub = split.row()
282
283         sub.prop(pchan, "ik_limit_z", text="Limit")
284         sub.active = pchan.ik_dof_z and pchan.has_ik
285         sub = split.row(align=True)
286         sub.prop(pchan, "ik_min_z", text="")
287         sub.prop(pchan, "ik_max_z", text="")
288         sub.active = pchan.ik_dof_z and pchan.ik_limit_z and pchan.has_ik
289         split = layout.split()
290         split.prop(pchan, "ik_stretch", text="Stretch", slider=True)
291         split.label()
292         split.active = pchan.has_ik
293
294         if ob.pose.ik_solver == 'ITASC':
295             split = layout.split()
296             col = split.column()
297             col.prop(pchan, "ik_rot_control", text="Control Rotation")
298             col.active = pchan.has_ik
299             col = split.column()
300             col.prop(pchan, "ik_rot_weight", text="Weight", slider=True)
301             col.active = pchan.has_ik
302             # not supported yet
303             #row = layout.row()
304             #row.prop(pchan, "ik_lin_control", text="Joint Size")
305             #row.prop(pchan, "ik_lin_weight", text="Weight", slider=True)
306
307
308 class BONE_PT_deform(BoneButtonsPanel, bpy.types.Panel):
309     bl_label = "Deform"
310     bl_default_closed = True
311
312     def draw_header(self, context):
313         bone = context.bone
314
315         if not bone:
316             bone = context.edit_bone
317
318         self.layout.prop(bone, "deform", text="")
319
320     def draw(self, context):
321         layout = self.layout
322
323         bone = context.bone
324
325         if not bone:
326             bone = context.edit_bone
327
328         layout.active = bone.deform
329
330         split = layout.split()
331
332         col = split.column()
333         col.label(text="Envelope:")
334
335         sub = col.column(align=True)
336         sub.prop(bone, "envelope_distance", text="Distance")
337         sub.prop(bone, "envelope_weight", text="Weight")
338         col.prop(bone, "multiply_vertexgroup_with_envelope", text="Multiply")
339
340         sub = col.column(align=True)
341         sub.label(text="Radius:")
342         sub.prop(bone, "head_radius", text="Head")
343         sub.prop(bone, "tail_radius", text="Tail")
344
345         col = split.column()
346         col.label(text="Curved Bones:")
347
348         sub = col.column(align=True)
349         sub.prop(bone, "bbone_segments", text="Segments")
350         sub.prop(bone, "bbone_in", text="Ease In")
351         sub.prop(bone, "bbone_out", text="Ease Out")
352
353         col.label(text="Offset:")
354         col.prop(bone, "cyclic_offset")
355
356
357 def register():
358     pass
359
360
361 def unregister():
362     pass
363
364 if __name__ == "__main__":
365     register()