a8c7201c45f8544294624db8ddcf07174fc707fa
[blender-staging.git] / release / scripts / ui / properties_object_constraint.py
1 # This software is distributable under the terms of the GNU
2 # General Public License (GPL) v2, the text of which can be found at
3 # http://www.gnu.org/copyleft/gpl.html. Installing, importing or otherwise
4 # using this module constitutes acceptance of the terms of this License.
5
6
7 import bpy
8
9 class ConstraintButtonsPanel(bpy.types.Panel):
10     bl_space_type = 'PROPERTIES'
11     bl_region_type = 'WINDOW'
12     bl_context = "constraint"
13
14     def draw_constraint(self, context, con):
15         layout = self.layout
16
17         box = layout.template_constraint(con)
18
19         if box:
20             # match enum type to our functions, avoids a lookup table.
21             getattr(self, con.type)(context, box, con)
22
23             # show/key buttons here are most likely obsolete now, with
24             # keyframing functionality being part of every button
25             if con.type not in ('RIGID_BODY_JOINT', 'NULL'):
26                 box.itemR(con, "influence")
27
28     def space_template(self, layout, con, target=True, owner=True):
29         if target or owner:
30             row = layout.row()
31
32             row.itemL(text="Convert:")
33
34             if target:
35                 row.itemR(con, "target_space", text="")
36
37             if target and owner:
38                 row.itemL(icon='ICON_ARROW_LEFTRIGHT')
39
40             if owner:
41                 row.itemR(con, "owner_space", text="")
42
43     def target_template(self, layout, con, subtargets=True):
44         layout.itemR(con, "target") # XXX limiting settings for only 'curves' or some type of object
45
46         if con.target and subtargets:
47             if con.target.type == 'ARMATURE':
48                 layout.item_pointerR(con, "subtarget", con.target.data, "bones", text="Bone")
49
50                 if con.type == 'COPY_LOCATION':
51                     row = layout.row()
52                     row.itemL(text="Head/Tail:")
53                     row.itemR(con, "head_tail", text="")
54             elif con.target.type in ('MESH', 'LATTICE'):
55                 layout.item_pointerR(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
56
57     def ik_template(self, layout, con):
58         # only used for iTaSC
59         layout.itemR(con, "pole_target")
60
61         if con.pole_target and con.pole_target.type == 'ARMATURE':
62             layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
63
64         if con.pole_target:
65             row = layout.row()
66             row.itemL()
67             row.itemR(con, "pole_angle")
68
69         split = layout.split(percentage=0.33)
70         col = split.column()
71         col.itemR(con, "tail")
72         col.itemR(con, "stretch")
73
74         col = split.column()
75         col.itemR(con, "chain_length")
76         col.itemR(con, "targetless")
77
78     def CHILD_OF(self, context, layout, con):
79         self.target_template(layout, con)
80
81         split = layout.split()
82
83         col = split.column()
84         col.itemL(text="Location:")
85         col.itemR(con, "locationx", text="X")
86         col.itemR(con, "locationy", text="Y")
87         col.itemR(con, "locationz", text="Z")
88
89         col = split.column()
90         col.itemL(text="Rotation:")
91         col.itemR(con, "rotationx", text="X")
92         col.itemR(con, "rotationy", text="Y")
93         col.itemR(con, "rotationz", text="Z")
94
95         col = split.column()
96         col.itemL(text="Scale:")
97         col.itemR(con, "sizex", text="X")
98         col.itemR(con, "sizey", text="Y")
99         col.itemR(con, "sizez", text="Z")
100
101         row = layout.row()
102         row.itemO("constraint.childof_set_inverse")
103         row.itemO("constraint.childof_clear_inverse")
104
105     def TRACK_TO(self, context, layout, con):
106         self.target_template(layout, con)
107
108         row = layout.row()
109         row.itemL(text="To:")
110         row.itemR(con, "track", expand=True)
111
112         row = layout.row()
113         #row.itemR(con, "up", text="Up", expand=True) # XXX: up and expand don't play nice together
114         row.itemR(con, "up", text="Up")
115         row.itemR(con, "target_z")
116
117         self.space_template(layout, con)
118
119     def IK(self, context, layout, con):
120         if context.object.pose.ik_solver == "ITASC":
121             layout.itemR(con, "ik_type")
122             getattr(self, "IK_"+con.ik_type)(context, layout, con)
123         else:
124             # Legacy IK constraint
125             self.target_template(layout, con)
126             layout.itemR(con, "pole_target")
127
128             if con.pole_target and con.pole_target.type == 'ARMATURE':
129                 layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
130
131             if con.pole_target:
132                 row = layout.row()
133                 row.itemL()
134                 row.itemR(con, "pole_angle")
135
136             split = layout.split()
137             col = split.column()
138             col.itemR(con, "tail")
139             col.itemR(con, "stretch")
140
141             col = split.column()
142             col.itemR(con, "iterations")
143             col.itemR(con, "chain_length")
144
145             split = layout.split()
146             col = split.column()
147             col.itemL()
148             col.itemR(con, "targetless")
149             col.itemR(con, "rotation")
150
151             col = split.column()
152             col.itemL(text="Weight:")
153             col.itemR(con, "weight", text="Position", slider=True)
154             sub = col.column()
155             sub.active = con.rotation
156             sub.itemR(con, "orient_weight", text="Rotation", slider=True)
157
158     def IK_COPY_POSE(self, context, layout, con):
159         self.target_template(layout, con)
160         self.ik_template(layout, con)
161
162         row = layout.row()
163         row.itemL(text="Axis Ref:")
164         row.itemR(con, "axis_reference", expand=True)
165         split = layout.split(percentage=0.33)
166         split.row().itemR(con, "position")
167         row = split.row()
168         row.itemR(con, "weight", text="Weight", slider=True)
169         row.active = con.position
170         split = layout.split(percentage=0.33)
171         row = split.row()
172         row.itemL(text="Lock:")
173         row = split.row()
174         row.itemR(con, "pos_lock_x", text="X")
175         row.itemR(con, "pos_lock_y", text="Y")
176         row.itemR(con, "pos_lock_z", text="Z")
177         split.active = con.position
178
179         split = layout.split(percentage=0.33)
180         split.row().itemR(con, "rotation")
181         row = split.row()
182         row.itemR(con, "orient_weight", text="Weight", slider=True)
183         row.active = con.rotation
184         split = layout.split(percentage=0.33)
185         row = split.row()
186         row.itemL(text="Lock:")
187         row = split.row()
188         row.itemR(con, "rot_lock_x", text="X")
189         row.itemR(con, "rot_lock_y", text="Y")
190         row.itemR(con, "rot_lock_z", text="Z")
191         split.active = con.rotation
192
193     def IK_DISTANCE(self, context, layout, con):
194         self.target_template(layout, con)
195         self.ik_template(layout, con)
196
197         layout.itemR(con, "limit_mode")
198         row = layout.row()
199         row.itemR(con, "weight", text="Weight", slider=True)
200         row.itemR(con, "distance", text="Distance", slider=True)
201
202     def FOLLOW_PATH(self, context, layout, con):
203         self.target_template(layout, con)
204
205         split = layout.split()
206
207         col = split.column()
208         col.itemR(con, "use_curve_follow")
209         col.itemR(con, "use_curve_radius")
210
211         col = split.column()
212         col.itemR(con, "use_fixed_position")
213         if con.use_fixed_position:
214             col.itemR(con, "offset_factor", text="Offset")
215         else:
216             col.itemR(con, "offset")
217
218         row = layout.row()
219         row.itemL(text="Forward:")
220         row.itemR(con, "forward", expand=True)
221
222         row = layout.row()
223         row.itemR(con, "up", text="Up")
224         row.itemL()
225
226     def LIMIT_ROTATION(self, context, layout, con):
227
228         split = layout.split()
229
230         col = split.column()
231         col.itemR(con, "use_limit_x")
232         sub = col.column()
233         sub.active = con.use_limit_x
234         sub.itemR(con, "minimum_x", text="Min")
235         sub.itemR(con, "maximum_x", text="Max")
236
237         col = split.column()
238         col.itemR(con, "use_limit_y")
239         sub = col.column()
240         sub.active = con.use_limit_y
241         sub.itemR(con, "minimum_y", text="Min")
242         sub.itemR(con, "maximum_y", text="Max")
243
244         col = split.column()
245         col.itemR(con, "use_limit_z")
246         sub = col.column()
247         sub.active = con.use_limit_z
248         sub.itemR(con, "minimum_z", text="Min")
249         sub.itemR(con, "maximum_z", text="Max")
250
251         row = layout.row()
252         row.itemR(con, "limit_transform")
253         row.itemL()
254
255         row = layout.row()
256         row.itemL(text="Convert:")
257         row.itemR(con, "owner_space", text="")
258
259     def LIMIT_LOCATION(self, context, layout, con):
260         split = layout.split()
261
262         col = split.column()
263         col.itemR(con, "use_minimum_x")
264         sub = col.column()
265         sub.active = con.use_minimum_x
266         sub.itemR(con, "minimum_x", text="")
267         col.itemR(con, "use_maximum_x")
268         sub = col.column()
269         sub.active = con.use_maximum_x
270         sub.itemR(con, "maximum_x", text="")
271
272         col = split.column()
273         col.itemR(con, "use_minimum_y")
274         sub = col.column()
275         sub.active = con.use_minimum_y
276         sub.itemR(con, "minimum_y", text="")
277         col.itemR(con, "use_maximum_y")
278         sub = col.column()
279         sub.active = con.use_maximum_y
280         sub.itemR(con, "maximum_y", text="")
281
282         col = split.column()
283         col.itemR(con, "use_minimum_z")
284         sub = col.column()
285         sub.active = con.use_minimum_z
286         sub.itemR(con, "minimum_z", text="")
287         col.itemR(con, "use_maximum_z")
288         sub = col.column()
289         sub.active = con.use_maximum_z
290         sub.itemR(con, "maximum_z", text="")
291
292         row = layout.row()
293         row.itemR(con, "limit_transform")
294         row.itemL()
295
296         row = layout.row()
297         row.itemL(text="Convert:")
298         row.itemR(con, "owner_space", text="")
299
300     def LIMIT_SCALE(self, context, layout, con):
301         split = layout.split()
302
303         col = split.column()
304         col.itemR(con, "use_minimum_x")
305         sub = col.column()
306         sub.active = con.use_minimum_x
307         sub.itemR(con, "minimum_x", text="")
308         col.itemR(con, "use_maximum_x")
309         sub = col.column()
310         sub.active = con.use_maximum_x
311         sub.itemR(con, "maximum_x", text="")
312
313         col = split.column()
314         col.itemR(con, "use_minimum_y")
315         sub = col.column()
316         sub.active = con.use_minimum_y
317         sub.itemR(con, "minimum_y", text="")
318         col.itemR(con, "use_maximum_y")
319         sub = col.column()
320         sub.active = con.use_maximum_y
321         sub.itemR(con, "maximum_y", text="")
322
323         col = split.column()
324         col.itemR(con, "use_minimum_z")
325         sub = col.column()
326         sub.active = con.use_minimum_z
327         sub.itemR(con, "minimum_z", text="")
328         col.itemR(con, "use_maximum_z")
329         sub = col.column()
330         sub.active = con.use_maximum_z
331         sub.itemR(con, "maximum_z", text="")
332
333         row = layout.row()
334         row.itemR(con, "limit_transform")
335         row.itemL()
336
337         row = layout.row()
338         row.itemL(text="Convert:")
339         row.itemR(con, "owner_space", text="")
340
341     def COPY_ROTATION(self, context, layout, con):
342         self.target_template(layout, con)
343
344         split = layout.split()
345
346         col = split.column()
347         col.itemR(con, "rotate_like_x", text="X")
348         sub = col.column()
349         sub.active = con.rotate_like_x
350         sub.itemR(con, "invert_x", text="Invert")
351
352         col = split.column()
353         col.itemR(con, "rotate_like_y", text="Y")
354         sub = col.column()
355         sub.active = con.rotate_like_y
356         sub.itemR(con, "invert_y", text="Invert")
357
358         col = split.column()
359         col.itemR(con, "rotate_like_z", text="Z")
360         sub = col.column()
361         sub.active = con.rotate_like_z
362         sub.itemR(con, "invert_z", text="Invert")
363
364         layout.itemR(con, "offset")
365
366         self.space_template(layout, con)
367
368     def COPY_LOCATION(self, context, layout, con):
369         self.target_template(layout, con)
370
371         split = layout.split()
372
373         col = split.column()
374         col.itemR(con, "locate_like_x", text="X")
375         sub = col.column()
376         sub.active = con.locate_like_x
377         sub.itemR(con, "invert_x", text="Invert")
378
379         col = split.column()
380         col.itemR(con, "locate_like_y", text="Y")
381         sub = col.column()
382         sub.active = con.locate_like_y
383         sub.itemR(con, "invert_y", text="Invert")
384
385         col = split.column()
386         col.itemR(con, "locate_like_z", text="Z")
387         sub = col.column()
388         sub.active = con.locate_like_z
389         sub.itemR(con, "invert_z", text="Invert")
390
391         layout.itemR(con, "offset")
392
393         self.space_template(layout, con)
394
395     def COPY_SCALE(self, context, layout, con):
396         self.target_template(layout, con)
397
398         row = layout.row(align=True)
399         row.itemR(con, "size_like_x", text="X")
400         row.itemR(con, "size_like_y", text="Y")
401         row.itemR(con, "size_like_z", text="Z")
402
403         layout.itemR(con, "offset")
404
405         self.space_template(layout, con)
406
407     #def SCRIPT(self, context, layout, con):
408
409     def ACTION(self, context, layout, con):
410         self.target_template(layout, con)
411
412         layout.itemR(con, "action")
413         layout.itemR(con, "transform_channel")
414
415         split = layout.split()
416
417         col = split.column(align=True)
418         col.itemR(con, "start_frame", text="Start")
419         col.itemR(con, "end_frame", text="End")
420
421         col = split.column(align=True)
422         col.itemR(con, "minimum", text="Min")
423         col.itemR(con, "maximum", text="Max")
424
425         row = layout.row()
426         row.itemL(text="Convert:")
427         row.itemR(con, "owner_space", text="")
428
429     def LOCKED_TRACK(self, context, layout, con):
430         self.target_template(layout, con)
431
432         row = layout.row()
433         row.itemL(text="To:")
434         row.itemR(con, "track", expand=True)
435
436         row = layout.row()
437         row.itemL(text="Lock:")
438         row.itemR(con, "locked", expand=True)
439
440     def LIMIT_DISTANCE(self, context, layout, con):
441         self.target_template(layout, con)
442
443         col = layout.column(align=True);
444         col.itemR(con, "distance")
445         col.itemO("constraint.limitdistance_reset")
446
447         row = layout.row()
448         row.itemL(text="Clamp Region:")
449         row.itemR(con, "limit_mode", text="")
450
451     def STRETCH_TO(self, context, layout, con):
452         self.target_template(layout, con)
453
454         row = layout.row()
455         row.itemR(con, "original_length", text="Rest Length")
456         row.itemO("constraint.stretchto_reset", text="Reset")
457
458         col = layout.column()
459         col.itemR(con, "bulge", text="Volume Variation")
460
461         row = layout.row()
462         row.itemL(text="Volume:")
463         row.itemR(con, "volume", expand=True)
464         row.itemL(text="Plane:")
465         row.itemR(con, "keep_axis", expand=True)
466
467     def FLOOR(self, context, layout, con):
468         self.target_template(layout, con)
469
470         row = layout.row()
471         row.itemR(con, "sticky")
472         row.itemR(con, "use_rotation")
473
474         layout.itemR(con, "offset")
475
476         row = layout.row()
477         row.itemL(text="Min/Max:")
478         row.itemR(con, "floor_location", expand=True)
479
480     def RIGID_BODY_JOINT(self, context, layout, con):
481         self.target_template(layout, con)
482
483         layout.itemR(con, "pivot_type")
484         layout.itemR(con, "child")
485
486         row = layout.row()
487         row.itemR(con, "disable_linked_collision", text="No Collision")
488         row.itemR(con, "draw_pivot", text="Display Pivot")
489
490         split = layout.split()
491
492         col = split.column(align=True)
493         col.itemL(text="Pivot:")
494         col.itemR(con, "pivot_x", text="X")
495         col.itemR(con, "pivot_y", text="Y")
496         col.itemR(con, "pivot_z", text="Z")
497
498         col = split.column(align=True)
499         col.itemL(text="Axis:")
500         col.itemR(con, "axis_x", text="X")
501         col.itemR(con, "axis_y", text="Y")
502         col.itemR(con, "axis_z", text="Z")
503
504         #Missing: Limit arrays (not wrapped in RNA yet)
505
506     def CLAMP_TO(self, context, layout, con):
507         self.target_template(layout, con)
508
509         row = layout.row()
510         row.itemL(text="Main Axis:")
511         row.itemR(con, "main_axis", expand=True)
512
513         row = layout.row()
514         row.itemR(con, "cyclic")
515
516     def TRANSFORM(self, context, layout, con):
517         self.target_template(layout, con)
518
519         layout.itemR(con, "extrapolate_motion", text="Extrapolate")
520
521         split = layout.split()
522
523         col = split.column()
524         col.itemL(text="Source:")
525         col.row().itemR(con, "map_from", expand=True)
526
527         sub = col.row(align=True)
528         sub.itemL(text="X:")
529         sub.itemR(con, "from_min_x", text="")
530         sub.itemR(con, "from_max_x", text="")
531
532         sub = col.row(align=True)
533         sub.itemL(text="Y:")
534         sub.itemR(con, "from_min_y", text="")
535         sub.itemR(con, "from_max_y", text="")
536
537         sub = col.row(align=True)
538         sub.itemL(text="Z:")
539         sub.itemR(con, "from_min_z", text="")
540         sub.itemR(con, "from_max_z", text="")
541
542         split = layout.split()
543
544         col = split.column()
545         col.itemL(text="Destination:")
546         col.row().itemR(con, "map_to", expand=True)
547
548         sub = col.row(align=True)
549         sub.itemR(con, "map_to_x_from", text="")
550         sub.itemR(con, "to_min_x", text="")
551         sub.itemR(con, "to_max_x", text="")
552
553         sub = col.row(align=True)
554         sub.itemR(con, "map_to_y_from", text="")
555         sub.itemR(con, "to_min_y", text="")
556         sub.itemR(con, "to_max_y", text="")
557
558         sub = col.row(align=True)
559         sub.itemR(con, "map_to_z_from", text="")
560         sub.itemR(con, "to_min_z", text="")
561         sub.itemR(con, "to_max_z", text="")
562
563         self.space_template(layout, con)
564
565     def SHRINKWRAP (self, context, layout, con):
566         self.target_template(layout, con)
567
568         layout.itemR(con, "distance")
569         layout.itemR(con, "shrinkwrap_type")
570
571         if con.shrinkwrap_type == 'PROJECT':
572             row = layout.row(align=True)
573             row.itemR(con, "axis_x")
574             row.itemR(con, "axis_y")
575             row.itemR(con, "axis_z")
576
577     def DAMPED_TRACK(self, context, layout, con):
578         self.target_template(layout, con)
579
580         row = layout.row()
581         row.itemL(text="To:")
582         row.itemR(con, "track", expand=True)
583
584 class OBJECT_PT_constraints(ConstraintButtonsPanel):
585     bl_label = "Constraints"
586     bl_context = "constraint"
587
588     def poll(self, context):
589         return (context.object)
590
591     def draw(self, context):
592         layout = self.layout
593         ob = context.object
594
595         row = layout.row()
596         row.item_menu_enumO("object.constraint_add", "type")
597         row.itemL();
598
599         for con in ob.constraints:
600             self.draw_constraint(context, con)
601
602 class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
603     bl_label = "Inverse Kinematics"
604     bl_default_closed = True
605     bl_context = "bone_constraint"
606
607     def poll(self, context):
608         ob = context.object
609         bone = context.bone
610
611         if ob and bone:
612             pchan = ob.pose.pose_channels[bone.name]
613             return pchan.has_ik
614
615         return False
616
617     def draw(self, context):
618         layout = self.layout
619
620         ob = context.object
621         bone = context.bone
622         pchan = ob.pose.pose_channels[bone.name]
623
624         row = layout.row()
625         row.itemR(ob.pose, "ik_solver")
626
627         split = layout.split(percentage=0.25)
628         split.itemR(pchan, "ik_dof_x", text="X")
629         row = split.row()
630         row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
631         row.active = pchan.ik_dof_x
632
633         split = layout.split(percentage=0.25)
634         row = split.row()
635         row.itemR(pchan, "ik_limit_x", text="Limit")
636         row.active = pchan.ik_dof_x
637         row = split.row(align=True)
638         row.itemR(pchan, "ik_min_x", text="")
639         row.itemR(pchan, "ik_max_x", text="")
640         row.active = pchan.ik_dof_x and pchan.ik_limit_x
641
642         split = layout.split(percentage=0.25)
643         split.itemR(pchan, "ik_dof_y", text="Y")
644         row = split.row()
645         row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
646         row.active = pchan.ik_dof_y
647
648         split = layout.split(percentage=0.25)
649         row = split.row()
650         row.itemR(pchan, "ik_limit_y", text="Limit")
651         row.active = pchan.ik_dof_y
652         row = split.row(align=True)
653         row.itemR(pchan, "ik_min_y", text="")
654         row.itemR(pchan, "ik_max_y", text="")
655         row.active = pchan.ik_dof_y and pchan.ik_limit_y
656
657         split = layout.split(percentage=0.25)
658         split.itemR(pchan, "ik_dof_z", text="Z")
659         row = split.row()
660         row.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
661         row.active = pchan.ik_dof_z
662
663         split = layout.split(percentage=0.25)
664         row = split.row()
665         row.itemR(pchan, "ik_limit_z", text="Limit")
666         row.active = pchan.ik_dof_z
667         row = split.row(align=True)
668         row.itemR(pchan, "ik_min_z", text="")
669         row.itemR(pchan, "ik_max_z", text="")
670         row.active = pchan.ik_dof_z and pchan.ik_limit_z
671         split = layout.split()
672         split.itemR(pchan, "ik_stretch", text="Stretch", slider=True)
673         split.itemL()
674
675         if ob.pose.ik_solver == "ITASC":
676             row = layout.row()
677             row.itemR(pchan, "ik_rot_control", text="Control Rotation")
678             row.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
679             # not supported yet
680             #row = layout.row()
681             #row.itemR(pchan, "ik_lin_control", text="Joint Size")
682             #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
683
684 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
685     bl_label = "iTaSC parameters"
686     bl_default_closed = True
687     bl_context = "bone_constraint"
688
689     def poll(self, context):
690         ob = context.object
691         bone = context.bone
692
693         if ob and bone:
694             pchan = ob.pose.pose_channels[bone.name]
695             return pchan.has_ik and ob.pose.ik_solver == "ITASC" and ob.pose.ik_param
696
697         return False
698
699     def draw(self, context):
700         layout = self.layout
701
702         ob = context.object
703         itasc = ob.pose.ik_param
704
705         layout.itemR(itasc, "mode", expand=True)
706         simulation = itasc.mode == "SIMULATION"
707         if simulation:
708             layout.itemL(text="Reiteration:")
709             layout.itemR(itasc, "reiteration", expand=True)
710
711         flow = layout.column_flow()
712         flow.itemR(itasc, "precision", text="Prec")
713         flow.itemR(itasc, "num_iter", text="Iter")
714         flow.active = not simulation or itasc.reiteration != "NEVER"
715
716         if simulation:
717             layout.itemR(itasc, "auto_step")
718             row = layout.row()
719             if itasc.auto_step:
720                 row.itemR(itasc, "min_step", text="Min")
721                 row.itemR(itasc, "max_step", text="Max")
722             else:
723                 row.itemR(itasc, "num_step")
724
725         layout.itemR(itasc, "solver")
726         if simulation:
727             layout.itemR(itasc, "feedback")
728             layout.itemR(itasc, "max_velocity")
729         if itasc.solver == "DLS":
730             row = layout.row()
731             row.itemR(itasc, "dampmax", text="Damp", slider=True)
732             row.itemR(itasc, "dampeps", text="Eps", slider=True)
733
734 class BONE_PT_constraints(ConstraintButtonsPanel):
735     bl_label = "Constraints"
736     bl_context = "bone_constraint"
737
738     def poll(self, context):
739         ob = context.object
740         return (ob and ob.type == 'ARMATURE' and context.bone)
741
742     def draw(self, context):
743         layout = self.layout
744
745         ob = context.object
746         pchan = ob.pose.pose_channels[context.bone.name]
747
748         row = layout.row()
749         row.item_menu_enumO("pose.constraint_add", "type")
750         row.itemL();
751
752         for con in pchan.constraints:
753             self.draw_constraint(context, con)
754
755 bpy.types.register(OBJECT_PT_constraints)
756 bpy.types.register(BONE_PT_iksolver_itasc)
757 bpy.types.register(BONE_PT_inverse_kinematics)
758 bpy.types.register(BONE_PT_constraints)