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