b5352abafa76a65d634712d7c575eebb519d5d95
[blender.git] / release / scripts / ui / properties_object_constraint.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
22 narrowui = bpy.context.user_preferences.view.properties_width_check
23 narrowcon = 260
24
25
26 class ConstraintButtonsPanel():
27     bl_space_type = 'PROPERTIES'
28     bl_region_type = 'WINDOW'
29     bl_context = "constraint"
30
31     def draw_constraint(self, context, con):
32         layout = self.layout
33
34         wide_ui = context.region.width > narrowui
35         compact_con = context.region.width < narrowcon
36         box = layout.template_constraint(con, compact=compact_con)
37
38         if box:
39             # match enum type to our functions, avoids a lookup table.
40             getattr(self, con.type)(context, box, con, wide_ui)
41
42             if con.type not in ('RIGID_BODY_JOINT', 'NULL'):
43                 box.prop(con, "influence")
44
45     def space_template(self, layout, con, wide_ui, target=True, owner=True):
46         if target or owner:
47
48             split = layout.split(percentage=0.2)
49
50             if wide_ui:
51                 split.label(text="Space:")
52                 row = split.row()
53             else:
54                 row = layout.row()
55
56
57             if target:
58                 row.prop(con, "target_space", text="")
59
60             if wide_ui:
61                 if target and owner:
62                     row.label(icon='ARROW_LEFTRIGHT')
63             else:
64                 row = layout.row()
65             if owner:
66                 row.prop(con, "owner_space", text="")
67
68     def target_template(self, layout, con, wide_ui, subtargets=True):
69         if wide_ui:
70             layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
71         else:
72             layout.prop(con, "target", text="")
73
74         if con.target and subtargets:
75             if con.target.type == 'ARMATURE':
76                 if wide_ui:
77                     layout.prop_object(con, "subtarget", con.target.data, "bones", text="Bone")
78                 else:
79                     layout.prop_object(con, "subtarget", con.target.data, "bones", text="")
80
81                 if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO', 'PIVOT'):
82                     row = layout.row()
83                     row.label(text="Head/Tail:")
84                     row.prop(con, "head_tail", text="")
85             elif con.target.type in ('MESH', 'LATTICE'):
86                 layout.prop_object(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
87
88     def ik_template(self, layout, con, wide_ui):
89         # only used for iTaSC
90         layout.prop(con, "pole_target")
91
92         if con.pole_target and con.pole_target.type == 'ARMATURE':
93             layout.prop_object(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
94
95         if con.pole_target:
96             row = layout.row()
97             row.label()
98             row.prop(con, "pole_angle")
99
100         split = layout.split(percentage=0.33)
101         col = split.column()
102         col.prop(con, "use_tail")
103         col.prop(con, "use_stretch")
104
105         col = split.column()
106         col.prop(con, "chain_length")
107         col.prop(con, "use_target")
108
109     def CHILD_OF(self, context, layout, con, wide_ui):
110         self.target_template(layout, con, wide_ui)
111
112         split = layout.split()
113
114         col = split.column()
115         col.label(text="Location:")
116         col.prop(con, "use_location_x", text="X")
117         col.prop(con, "use_location_y", text="Y")
118         col.prop(con, "use_location_z", text="Z")
119
120         col = split.column()
121         col.label(text="Rotation:")
122         col.prop(con, "use_rotation_x", text="X")
123         col.prop(con, "use_rotation_y", text="Y")
124         col.prop(con, "use_rotation_z", text="Z")
125
126         col = split.column()
127         col.label(text="Scale:")
128         col.prop(con, "use_scale_x", text="X")
129         col.prop(con, "use_scale_y", text="Y")
130         col.prop(con, "use_scale_z", text="Z")
131
132         split = layout.split()
133
134         col = split.column()
135         col.operator("constraint.childof_set_inverse")
136
137         if wide_ui:
138             col = split.column()
139         col.operator("constraint.childof_clear_inverse")
140
141     def TRACK_TO(self, context, layout, con, wide_ui):
142         self.target_template(layout, con, wide_ui)
143
144         row = layout.row()
145         if wide_ui:
146             row.label(text="To:")
147         row.prop(con, "track", expand=True)
148
149         split = layout.split()
150
151         col = split.column()
152         col.prop(con, "up", text="Up")
153
154         if wide_ui:
155             col = split.column()
156         col.prop(con, "target_z")
157
158         self.space_template(layout, con, wide_ui)
159
160     def IK(self, context, layout, con, wide_ui):
161         if context.object.pose.ik_solver == "ITASC":
162             layout.prop(con, "ik_type")
163             getattr(self, 'IK_' + con.ik_type)(context, layout, con, wide_ui)
164         else:
165             # Legacy IK constraint
166             self.target_template(layout, con, wide_ui)
167             if wide_ui:
168                 layout.prop(con, "pole_target")
169             else:
170                 layout.prop(con, "pole_target", text="")
171             if con.pole_target and con.pole_target.type == 'ARMATURE':
172                 if wide_ui:
173                     layout.prop_object(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
174                 else:
175                     layout.prop_object(con, "pole_subtarget", con.pole_target.data, "bones", text="")
176
177             if con.pole_target:
178                 row = layout.row()
179                 row.prop(con, "pole_angle")
180                 if wide_ui:
181                     row.label()
182
183             split = layout.split()
184             col = split.column()
185             col.prop(con, "iterations")
186             col.prop(con, "chain_length")
187
188             col.label(text="Weight:")
189             col.prop(con, "weight", text="Position", slider=True)
190             sub = col.column()
191             sub.active = con.use_rotation
192             sub.prop(con, "orient_weight", text="Rotation", slider=True)
193
194             if wide_ui:
195                 col = split.column()
196             col.prop(con, "use_tail")
197             col.prop(con, "use_stretch")
198             col.separator()
199             col.prop(con, "use_target")
200             col.prop(con, "use_rotation")
201
202     def IK_COPY_POSE(self, context, layout, con, wide_ui):
203         self.target_template(layout, con, wide_ui)
204         self.ik_template(layout, con, wide_ui)
205
206         row = layout.row()
207         row.label(text="Axis Ref:")
208         row.prop(con, "axis_reference", expand=True)
209         split = layout.split(percentage=0.33)
210         split.row().prop(con, "use_position")
211         row = split.row()
212         row.prop(con, "weight", text="Weight", slider=True)
213         row.active = con.use_position
214         split = layout.split(percentage=0.33)
215         row = split.row()
216         row.label(text="Lock:")
217         row = split.row()
218         row.prop(con, "pos_lock_x", text="X")
219         row.prop(con, "pos_lock_y", text="Y")
220         row.prop(con, "pos_lock_z", text="Z")
221         split.active = con.use_position
222
223         split = layout.split(percentage=0.33)
224         split.row().prop(con, "use_rotation")
225         row = split.row()
226         row.prop(con, "orient_weight", text="Weight", slider=True)
227         row.active = con.use_rotation
228         split = layout.split(percentage=0.33)
229         row = split.row()
230         row.label(text="Lock:")
231         row = split.row()
232         row.prop(con, "rot_lock_x", text="X")
233         row.prop(con, "rot_lock_y", text="Y")
234         row.prop(con, "rot_lock_z", text="Z")
235         split.active = con.use_rotation
236
237     def IK_DISTANCE(self, context, layout, con, wide_ui):
238         self.target_template(layout, con, wide_ui)
239         self.ik_template(layout, con, wide_ui)
240
241         layout.prop(con, "limit_mode")
242         row = layout.row()
243         row.prop(con, "weight", text="Weight", slider=True)
244         row.prop(con, "distance", text="Distance", slider=True)
245
246     def FOLLOW_PATH(self, context, layout, con, wide_ui):
247         self.target_template(layout, con, wide_ui)
248
249         split = layout.split()
250
251         col = split.column()
252         col.prop(con, "use_curve_follow")
253         col.prop(con, "use_curve_radius")
254
255         if wide_ui:
256             col = split.column()
257         col.prop(con, "use_fixed_position")
258         if con.use_fixed_position:
259             col.prop(con, "offset_factor", text="Offset")
260         else:
261             col.prop(con, "offset")
262
263         row = layout.row()
264         if wide_ui:
265             row.label(text="Forward:")
266         row.prop(con, "forward", expand=True)
267
268         row = layout.row()
269         row.prop(con, "up", text="Up")
270         if wide_ui:
271             row.label()
272
273     def LIMIT_ROTATION(self, context, layout, con, wide_ui):
274
275         split = layout.split()
276
277         col = split.column(align=True)
278         col.prop(con, "use_limit_x")
279         sub = col.column()
280         sub.active = con.use_limit_x
281         sub.prop(con, "minimum_x", text="Min")
282         sub.prop(con, "maximum_x", text="Max")
283
284         if wide_ui:
285             col = split.column(align=True)
286         col.prop(con, "use_limit_y")
287         sub = col.column()
288         sub.active = con.use_limit_y
289         sub.prop(con, "minimum_y", text="Min")
290         sub.prop(con, "maximum_y", text="Max")
291
292         if wide_ui:
293             col = split.column(align=True)
294         col.prop(con, "use_limit_z")
295         sub = col.column()
296         sub.active = con.use_limit_z
297         sub.prop(con, "minimum_z", text="Min")
298         sub.prop(con, "maximum_z", text="Max")
299
300         row = layout.row()
301         row.prop(con, "limit_transform")
302         if wide_ui:
303             row.label()
304
305         row = layout.row()
306         if wide_ui:
307             row.label(text="Convert:")
308         row.prop(con, "owner_space", text="")
309
310     def LIMIT_LOCATION(self, context, layout, con, wide_ui):
311         split = layout.split()
312
313         col = split.column()
314         col.prop(con, "use_minimum_x")
315         sub = col.column()
316         sub.active = con.use_minimum_x
317         sub.prop(con, "minimum_x", text="")
318         col.prop(con, "use_maximum_x")
319         sub = col.column()
320         sub.active = con.use_maximum_x
321         sub.prop(con, "maximum_x", text="")
322
323         if wide_ui:
324             col = split.column()
325         col.prop(con, "use_minimum_y")
326         sub = col.column()
327         sub.active = con.use_minimum_y
328         sub.prop(con, "minimum_y", text="")
329         col.prop(con, "use_maximum_y")
330         sub = col.column()
331         sub.active = con.use_maximum_y
332         sub.prop(con, "maximum_y", text="")
333
334         if wide_ui:
335             col = split.column()
336         col.prop(con, "use_minimum_z")
337         sub = col.column()
338         sub.active = con.use_minimum_z
339         sub.prop(con, "minimum_z", text="")
340         col.prop(con, "use_maximum_z")
341         sub = col.column()
342         sub.active = con.use_maximum_z
343         sub.prop(con, "maximum_z", text="")
344
345         row = layout.row()
346         row.prop(con, "limit_transform")
347         if wide_ui:
348             row.label()
349
350         row = layout.row()
351         if wide_ui:
352             row.label(text="Convert:")
353         row.prop(con, "owner_space", text="")
354
355     def LIMIT_SCALE(self, context, layout, con, wide_ui):
356         split = layout.split()
357
358         col = split.column()
359         col.prop(con, "use_minimum_x")
360         sub = col.column()
361         sub.active = con.use_minimum_x
362         sub.prop(con, "minimum_x", text="")
363         col.prop(con, "use_maximum_x")
364         sub = col.column()
365         sub.active = con.use_maximum_x
366         sub.prop(con, "maximum_x", text="")
367
368         if wide_ui:
369             col = split.column()
370         col.prop(con, "use_minimum_y")
371         sub = col.column()
372         sub.active = con.use_minimum_y
373         sub.prop(con, "minimum_y", text="")
374         col.prop(con, "use_maximum_y")
375         sub = col.column()
376         sub.active = con.use_maximum_y
377         sub.prop(con, "maximum_y", text="")
378
379         if wide_ui:
380             col = split.column()
381         col.prop(con, "use_minimum_z")
382         sub = col.column()
383         sub.active = con.use_minimum_z
384         sub.prop(con, "minimum_z", text="")
385         col.prop(con, "use_maximum_z")
386         sub = col.column()
387         sub.active = con.use_maximum_z
388         sub.prop(con, "maximum_z", text="")
389
390         row = layout.row()
391         row.prop(con, "limit_transform")
392         if wide_ui:
393             row.label()
394
395         row = layout.row()
396         if wide_ui:
397             row.label(text="Convert:")
398         row.prop(con, "owner_space", text="")
399
400     def COPY_ROTATION(self, context, layout, con, wide_ui):
401         self.target_template(layout, con, wide_ui)
402
403         split = layout.split()
404
405         col = split.column()
406         col.prop(con, "use_x", text="X")
407         sub = col.column()
408         sub.active = con.use_x
409         sub.prop(con, "invert_x", text="Invert")
410
411         col = split.column()
412         col.prop(con, "use_y", text="Y")
413         sub = col.column()
414         sub.active = con.use_y
415         sub.prop(con, "invert_y", text="Invert")
416
417         col = split.column()
418         col.prop(con, "use_z", text="Z")
419         sub = col.column()
420         sub.active = con.use_z
421         sub.prop(con, "invert_z", text="Invert")
422
423         layout.prop(con, "use_offset")
424
425         self.space_template(layout, con, wide_ui)
426
427     def COPY_LOCATION(self, context, layout, con, wide_ui):
428         self.target_template(layout, con, wide_ui)
429
430         split = layout.split()
431
432         col = split.column()
433         col.prop(con, "use_x", text="X")
434         sub = col.column()
435         sub.active = con.use_x
436         sub.prop(con, "invert_x", text="Invert")
437
438         col = split.column()
439         col.prop(con, "use_y", text="Y")
440         sub = col.column()
441         sub.active = con.use_y
442         sub.prop(con, "invert_y", text="Invert")
443
444         col = split.column()
445         col.prop(con, "use_z", text="Z")
446         sub = col.column()
447         sub.active = con.use_z
448         sub.prop(con, "invert_z", text="Invert")
449
450         layout.prop(con, "use_offset")
451
452         self.space_template(layout, con, wide_ui)
453
454     def COPY_SCALE(self, context, layout, con, wide_ui):
455         self.target_template(layout, con, wide_ui)
456
457         row = layout.row(align=True)
458         row.prop(con, "use_x", text="X")
459         row.prop(con, "use_y", text="Y")
460         row.prop(con, "use_z", text="Z")
461
462         layout.prop(con, "use_offset")
463
464         self.space_template(layout, con, wide_ui)
465
466     def MAINTAIN_VOLUME(self, context, layout, con, wide_ui):
467
468         row = layout.row()
469         if wide_ui:
470             row.label(text="Free:")
471         row.prop(con, "axis", expand=True)
472
473         layout.prop(con, "volume")
474
475         self.space_template(layout, con, wide_ui)
476
477     def COPY_TRANSFORMS(self, context, layout, con, wide_ui):
478         self.target_template(layout, con, wide_ui)
479
480         self.space_template(layout, con, wide_ui)
481
482     #def SCRIPT(self, context, layout, con):
483
484     def ACTION(self, context, layout, con, wide_ui):
485         self.target_template(layout, con, wide_ui)
486
487         if wide_ui:
488             layout.prop(con, "action")
489         else:
490             layout.prop(con, "action", text="")
491
492         if wide_ui:
493             layout.prop(con, "transform_channel")
494         else:
495             layout.prop(con, "transform_channel", text="")
496
497         split = layout.split()
498
499         col = split.column(align=True)
500         col.label(text="Action Length:")
501         col.prop(con, "frame_start", text="Start")
502         col.prop(con, "frame_end", text="End")
503
504         if wide_ui:
505             col = split.column(align=True)
506         col.label(text="Target Range:")
507         col.prop(con, "minimum", text="Min")
508         col.prop(con, "maximum", text="Max")
509
510         row = layout.row()
511         if wide_ui:
512             row.label(text="Convert:")
513         row.prop(con, "target_space", text="")
514
515     def LOCKED_TRACK(self, context, layout, con, wide_ui):
516         self.target_template(layout, con, wide_ui)
517
518         row = layout.row()
519         if wide_ui:
520             row.label(text="To:")
521         row.prop(con, "track", expand=True)
522
523         row = layout.row()
524         if wide_ui:
525             row.label(text="Lock:")
526         row.prop(con, "lock", expand=True)
527
528     def LIMIT_DISTANCE(self, context, layout, con, wide_ui):
529         self.target_template(layout, con, wide_ui)
530
531         col = layout.column(align=True)
532         col.prop(con, "distance")
533         col.operator("constraint.limitdistance_reset")
534
535         row = layout.row()
536         row.label(text="Clamp Region:")
537         row.prop(con, "limit_mode", text="")
538
539     def STRETCH_TO(self, context, layout, con, wide_ui):
540         self.target_template(layout, con, wide_ui)
541
542         split = layout.split()
543
544         col = split.column()
545         col.prop(con, "original_length", text="Rest Length")
546
547         if wide_ui:
548             col = split.column()
549         col.operator("constraint.stretchto_reset", text="Reset")
550
551         col = layout.column()
552         col.prop(con, "bulge", text="Volume Variation")
553
554         row = layout.row()
555         if wide_ui:
556             row.label(text="Volume:")
557         row.prop(con, "volume", expand=True)
558         if not wide_ui:
559             row = layout.row()
560         row.label(text="Plane:")
561         row.prop(con, "keep_axis", expand=True)
562
563     def FLOOR(self, context, layout, con, wide_ui):
564         self.target_template(layout, con, wide_ui)
565
566         split = layout.split()
567
568         col = split.column()
569         col.prop(con, "sticky")
570
571         if wide_ui:
572             col = split.column()
573         col.prop(con, "use_rotation")
574
575         layout.prop(con, "offset")
576
577         row = layout.row()
578         if wide_ui:
579             row.label(text="Min/Max:")
580         row.prop(con, "floor_location", expand=True)
581
582         self.space_template(layout, con, wide_ui)
583
584     def RIGID_BODY_JOINT(self, context, layout, con, wide_ui):
585         self.target_template(layout, con, wide_ui)
586
587         if wide_ui:
588             layout.prop(con, "pivot_type")
589         else:
590             layout.prop(con, "pivot_type", text="")
591         if wide_ui:
592             layout.prop(con, "child")
593         else:
594             layout.prop(con, "child", text="")
595
596         split = layout.split()
597
598         col = split.column()
599         col.prop(con, "disable_linked_collision", text="No Collision")
600
601         if wide_ui:
602             col = split.column()
603         col.prop(con, "draw_pivot", text="Display Pivot")
604
605         split = layout.split()
606
607         col = split.column(align=True)
608         col.label(text="Pivot:")
609         col.prop(con, "pivot_x", text="X")
610         col.prop(con, "pivot_y", text="Y")
611         col.prop(con, "pivot_z", text="Z")
612
613         if wide_ui:
614             col = split.column(align=True)
615         col.label(text="Axis:")
616         col.prop(con, "axis_x", text="X")
617         col.prop(con, "axis_y", text="Y")
618         col.prop(con, "axis_z", text="Z")
619
620         #Missing: Limit arrays (not wrapped in RNA yet)
621
622     def CLAMP_TO(self, context, layout, con, wide_ui):
623         self.target_template(layout, con, wide_ui)
624
625         row = layout.row()
626         if wide_ui:
627             row.label(text="Main Axis:")
628         row.prop(con, "main_axis", expand=True)
629
630         row = layout.row()
631         row.prop(con, "cyclic")
632
633     def TRANSFORM(self, context, layout, con, wide_ui):
634         self.target_template(layout, con, wide_ui)
635
636         layout.prop(con, "extrapolate_motion", text="Extrapolate")
637
638         col = layout.column()
639         col.row().label(text="Source:")
640         col.row().prop(con, "map_from", expand=True)
641
642         split = layout.split()
643
644         sub = split.column(align=True)
645         sub.label(text="X:")
646         sub.prop(con, "from_min_x", text="Min")
647         sub.prop(con, "from_max_x", text="Max")
648
649         if wide_ui:
650             sub = split.column(align=True)
651         sub.label(text="Y:")
652         sub.prop(con, "from_min_y", text="Min")
653         sub.prop(con, "from_max_y", text="Max")
654
655         if wide_ui:
656             sub = split.column(align=True)
657         sub.label(text="Z:")
658         sub.prop(con, "from_min_z", text="Min")
659         sub.prop(con, "from_max_z", text="Max")
660
661         split = layout.split()
662
663         col = split.column()
664         col.label(text="Destination:")
665         col.row().prop(con, "map_to", expand=True)
666
667         split = layout.split()
668
669         col = split.column()
670         col.label(text="X:")
671         col.row().prop(con, "map_to_x_from", expand=True)
672
673         sub = col.column(align=True)
674         sub.prop(con, "to_min_x", text="Min")
675         sub.prop(con, "to_max_x", text="Max")
676
677         if wide_ui:
678             col = split.column()
679         col.label(text="Y:")
680         col.row().prop(con, "map_to_y_from", expand=True)
681
682         sub = col.column(align=True)
683         sub.prop(con, "to_min_y", text="Min")
684         sub.prop(con, "to_max_y", text="Max")
685
686         if wide_ui:
687             col = split.column()
688         col.label(text="Z:")
689         col.row().prop(con, "map_to_z_from", expand=True)
690
691         sub = col.column(align=True)
692         sub.prop(con, "to_min_z", text="Min")
693         sub.prop(con, "to_max_z", text="Max")
694
695         self.space_template(layout, con, wide_ui)
696
697     def SHRINKWRAP(self, context, layout, con, wide_ui):
698         self.target_template(layout, con, wide_ui)
699
700         layout.prop(con, "distance")
701         layout.prop(con, "shrinkwrap_type")
702
703         if con.shrinkwrap_type == 'PROJECT':
704             row = layout.row(align=True)
705             row.prop(con, "use_x")
706             row.prop(con, "use_y")
707             row.prop(con, "use_z")
708
709     def DAMPED_TRACK(self, context, layout, con, wide_ui):
710         self.target_template(layout, con, wide_ui)
711
712         row = layout.row()
713         if wide_ui:
714             row.label(text="To:")
715         row.prop(con, "track", expand=True)
716
717     def SPLINE_IK(self, context, layout, con, wide_ui):
718         self.target_template(layout, con, wide_ui)
719
720         col = layout.column()
721         col.label(text="Spline Fitting:")
722         col.prop(con, "chain_length")
723         col.prop(con, "even_divisions")
724         col.prop(con, "chain_offset")
725
726         col = layout.column()
727         col.label(text="Chain Scaling:")
728         col.prop(con, "y_stretch")
729         if wide_ui:
730             col.prop(con, "xz_scaling_mode")
731         else:
732             col.prop(con, "xz_scaling_mode", text="")
733         col.prop(con, "use_curve_radius")
734
735     def PIVOT(self, context, layout, con, wide_ui):
736         self.target_template(layout, con, wide_ui)
737
738         if con.target:
739             col = layout.column()
740             col.prop(con, "offset", text="Pivot Offset")
741         else:
742             col = layout.column()
743             col.prop(con, "use_relative_position")
744             if con.use_relative_position:
745                 col.prop(con, "offset", text="Relative Pivot Point")
746             else:
747                 col.prop(con, "offset", text="Absolute Pivot Point")
748
749         col = layout.column()
750         col.prop(con, "enabled_rotation_range", text="Pivot When")
751
752 class OBJECT_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
753     bl_label = "Object Constraints"
754     bl_context = "constraint"
755
756     @staticmethod
757     def poll(context):
758         return (context.object)
759
760     def draw(self, context):
761         layout = self.layout
762
763         ob = context.object
764
765         layout.operator_menu_enum("object.constraint_add", "type")
766
767         for con in ob.constraints:
768             self.draw_constraint(context, con)
769
770
771 class BONE_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
772     bl_label = "Bone Constraints"
773     bl_context = "bone_constraint"
774
775     @staticmethod
776     def poll(context):
777         return (context.pose_bone)
778
779     def draw(self, context):
780         layout = self.layout
781
782         layout.operator_menu_enum("pose.constraint_add", "type")
783
784         for con in context.pose_bone.constraints:
785             self.draw_constraint(context, con)
786
787
788 def register():
789     pass
790
791
792 def unregister():
793     pass
794
795 if __name__ == "__main__":
796     register()