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