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