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