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