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