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