Cleanup: unused imports
[blender.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 from bpy.types import Panel
21
22
23 class ConstraintButtonsPanel:
24     bl_space_type = 'PROPERTIES'
25     bl_region_type = 'WINDOW'
26     bl_context = "constraint"
27
28     def draw_constraint(self, context, con):
29         layout = self.layout
30
31         box = layout.template_constraint(con)
32
33         if box:
34             # match enum type to our functions, avoids a lookup table.
35             getattr(self, con.type)(context, box, con)
36
37             if con.type not in {'RIGID_BODY_JOINT', 'NULL'}:
38                 box.prop(con, "influence")
39
40     @staticmethod
41     def space_template(layout, con, target=True, owner=True):
42         if target or owner:
43
44             split = layout.split(factor=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     @staticmethod
59     def target_template(layout, con, subtargets=True):
60         layout.prop(con, "target")  # XXX limiting settings for only 'curves' or some type of object
61
62         if con.target and subtargets:
63             if con.target.type == 'ARMATURE':
64                 layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
65
66                 if hasattr(con, "head_tail"):
67                     row = layout.row(align=True)
68                     row.label(text="Head/Tail:")
69                     row.prop(con, "head_tail", text="")
70                     # XXX icon, and only when bone has segments?
71                     row.prop(con, "use_bbone_shape", text="", icon='IPO_BEZIER')
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(factor=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(factor=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(factor=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(factor=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(factor=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         row = layout.row()
424         row.prop(con, "use_offset")
425         row = row.row()
426         row.active = con.use_offset
427         row.prop(con, "use_add")
428
429         self.space_template(layout, con)
430
431     def MAINTAIN_VOLUME(self, context, layout, con):
432
433         row = layout.row()
434         row.label(text="Free:")
435         row.prop(con, "free_axis", expand=True)
436
437         layout.prop(con, "volume")
438
439         row = layout.row()
440         row.label(text="Convert:")
441         row.prop(con, "owner_space", text="")
442
443     def COPY_TRANSFORMS(self, context, layout, con):
444         self.target_template(layout, con)
445
446         self.space_template(layout, con)
447
448     # def SCRIPT(self, context, layout, con):
449
450     def ACTION(self, context, layout, con):
451         self.target_template(layout, con)
452
453         split = layout.split()
454
455         col = split.column()
456         col.label(text="From Target:")
457         col.prop(con, "transform_channel", text="")
458         col.prop(con, "target_space", text="")
459
460         col = split.column()
461         col.label(text="To Action:")
462         col.prop(con, "action", text="")
463         col.prop(con, "use_bone_object_action")
464
465         split = layout.split()
466
467         col = split.column(align=True)
468         col.label(text="Target Range:")
469         col.prop(con, "min", text="Min")
470         col.prop(con, "max", text="Max")
471
472         col = split.column(align=True)
473         col.label(text="Action Range:")
474         col.prop(con, "frame_start", text="Start")
475         col.prop(con, "frame_end", text="End")
476
477     def LOCKED_TRACK(self, context, layout, con):
478         self.target_template(layout, con)
479
480         row = layout.row()
481         row.label(text="To:")
482         row.prop(con, "track_axis", expand=True)
483
484         row = layout.row()
485         row.label(text="Lock:")
486         row.prop(con, "lock_axis", expand=True)
487
488     def LIMIT_DISTANCE(self, context, layout, con):
489         self.target_template(layout, con)
490
491         col = layout.column(align=True)
492         col.prop(con, "distance")
493         col.operator("constraint.limitdistance_reset")
494
495         row = layout.row()
496         row.label(text="Clamp Region:")
497         row.prop(con, "limit_mode", text="")
498
499         row = layout.row()
500         row.prop(con, "use_transform_limit")
501         row.label()
502
503         self.space_template(layout, con)
504
505     def STRETCH_TO(self, context, layout, con):
506         self.target_template(layout, con)
507
508         row = layout.row()
509         row.prop(con, "rest_length", text="Rest Length")
510         row.operator("constraint.stretchto_reset", text="Reset")
511
512         layout.prop(con, "bulge", text="Volume Variation")
513         split = layout.split()
514         col = split.column(align=True)
515         col.prop(con, "use_bulge_min", text="Volume Min")
516         sub = col.column()
517         sub.active = con.use_bulge_min
518         sub.prop(con, "bulge_min", text="")
519         col = split.column(align=True)
520         col.prop(con, "use_bulge_max", text="Volume Max")
521         sub = col.column()
522         sub.active = con.use_bulge_max
523         sub.prop(con, "bulge_max", text="")
524         col = layout.column()
525         col.active = con.use_bulge_min or con.use_bulge_max
526         col.prop(con, "bulge_smooth", text="Smooth")
527
528         row = layout.row()
529         row.label(text="Volume:")
530         row.prop(con, "volume", expand=True)
531
532         row.label(text="Plane:")
533         row.prop(con, "keep_axis", expand=True)
534
535     def FLOOR(self, context, layout, con):
536         self.target_template(layout, con)
537
538         row = layout.row()
539         row.prop(con, "use_sticky")
540         row.prop(con, "use_rotation")
541
542         layout.prop(con, "offset")
543
544         row = layout.row()
545         row.label(text="Min/Max:")
546         row.prop(con, "floor_location", expand=True)
547
548         self.space_template(layout, con)
549
550     def RIGID_BODY_JOINT(self, context, layout, con):
551         self.target_template(layout, con, subtargets=False)
552
553         layout.prop(con, "pivot_type")
554         layout.prop(con, "child")
555
556         row = layout.row()
557         row.prop(con, "use_linked_collision", text="Linked Collision")
558         row.prop(con, "show_pivot", text="Display Pivot")
559
560         split = layout.split()
561
562         col = split.column(align=True)
563         col.label(text="Pivot:")
564         col.prop(con, "pivot_x", text="X")
565         col.prop(con, "pivot_y", text="Y")
566         col.prop(con, "pivot_z", text="Z")
567
568         col = split.column(align=True)
569         col.label(text="Axis:")
570         col.prop(con, "axis_x", text="X")
571         col.prop(con, "axis_y", text="Y")
572         col.prop(con, "axis_z", text="Z")
573
574         if con.pivot_type == 'CONE_TWIST':
575             layout.label(text="Limits:")
576             split = layout.split()
577
578             col = split.column()
579             col.prop(con, "use_angular_limit_x", text="Angle X")
580             sub = col.column()
581             sub.active = con.use_angular_limit_x
582             sub.prop(con, "limit_angle_max_x", text="")
583
584             col = split.column()
585             col.prop(con, "use_angular_limit_y", text="Angle Y")
586             sub = col.column()
587             sub.active = con.use_angular_limit_y
588             sub.prop(con, "limit_angle_max_y", text="")
589
590             col = split.column()
591             col.prop(con, "use_angular_limit_z", text="Angle Z")
592             sub = col.column()
593             sub.active = con.use_angular_limit_z
594             sub.prop(con, "limit_angle_max_z", text="")
595
596         elif con.pivot_type == 'GENERIC_6_DOF':
597             layout.label(text="Limits:")
598             split = layout.split()
599
600             col = split.column(align=True)
601             col.prop(con, "use_limit_x", text="X")
602             sub = col.column(align=True)
603             sub.active = con.use_limit_x
604             sub.prop(con, "limit_min_x", text="Min")
605             sub.prop(con, "limit_max_x", text="Max")
606
607             col = split.column(align=True)
608             col.prop(con, "use_limit_y", text="Y")
609             sub = col.column(align=True)
610             sub.active = con.use_limit_y
611             sub.prop(con, "limit_min_y", text="Min")
612             sub.prop(con, "limit_max_y", text="Max")
613
614             col = split.column(align=True)
615             col.prop(con, "use_limit_z", text="Z")
616             sub = col.column(align=True)
617             sub.active = con.use_limit_z
618             sub.prop(con, "limit_min_z", text="Min")
619             sub.prop(con, "limit_max_z", text="Max")
620
621             split = layout.split()
622
623             col = split.column(align=True)
624             col.prop(con, "use_angular_limit_x", text="Angle X")
625             sub = col.column(align=True)
626             sub.active = con.use_angular_limit_x
627             sub.prop(con, "limit_angle_min_x", text="Min")
628             sub.prop(con, "limit_angle_max_x", text="Max")
629
630             col = split.column(align=True)
631             col.prop(con, "use_angular_limit_y", text="Angle Y")
632             sub = col.column(align=True)
633             sub.active = con.use_angular_limit_y
634             sub.prop(con, "limit_angle_min_y", text="Min")
635             sub.prop(con, "limit_angle_max_y", text="Max")
636
637             col = split.column(align=True)
638             col.prop(con, "use_angular_limit_z", text="Angle Z")
639             sub = col.column(align=True)
640             sub.active = con.use_angular_limit_z
641             sub.prop(con, "limit_angle_min_z", text="Min")
642             sub.prop(con, "limit_angle_max_z", text="Max")
643
644         elif con.pivot_type == 'HINGE':
645             layout.label(text="Limits:")
646             split = layout.split()
647
648             row = split.row(align=True)
649             col = row.column()
650             col.prop(con, "use_angular_limit_x", text="Angle X")
651
652             col = row.column()
653             col.active = con.use_angular_limit_x
654             col.prop(con, "limit_angle_min_x", text="Min")
655             col = row.column()
656             col.active = con.use_angular_limit_x
657             col.prop(con, "limit_angle_max_x", text="Max")
658
659     def CLAMP_TO(self, context, layout, con):
660         self.target_template(layout, con)
661
662         row = layout.row()
663         row.label(text="Main Axis:")
664         row.prop(con, "main_axis", expand=True)
665
666         layout.prop(con, "use_cyclic")
667
668     def TRANSFORM(self, context, layout, con):
669         self.target_template(layout, con)
670
671         layout.prop(con, "use_motion_extrapolate", text="Extrapolate")
672
673         col = layout.column()
674         col.row().label(text="Source:")
675         col.row().prop(con, "map_from", expand=True)
676
677         split = layout.split()
678         ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
679
680         sub = split.column(align=True)
681         sub.label(text="X:")
682         sub.prop(con, "from_min_x" + ext, text="Min")
683         sub.prop(con, "from_max_x" + ext, text="Max")
684
685         sub = split.column(align=True)
686         sub.label(text="Y:")
687         sub.prop(con, "from_min_y" + ext, text="Min")
688         sub.prop(con, "from_max_y" + ext, text="Max")
689
690         sub = split.column(align=True)
691         sub.label(text="Z:")
692         sub.prop(con, "from_min_z" + ext, text="Min")
693         sub.prop(con, "from_max_z" + ext, text="Max")
694
695         col = layout.column()
696         row = col.row()
697         row.label(text="Source to Destination Mapping:")
698
699         # note: chr(187) is the ASCII arrow ( >> ). Blender Text Editor can't
700         # open it. Thus we are using the hard-coded value instead.
701         row = col.row()
702         row.prop(con, "map_to_x_from", expand=False, text="")
703         row.label(text=" %s    X" % chr(187))
704
705         row = col.row()
706         row.prop(con, "map_to_y_from", expand=False, text="")
707         row.label(text=" %s    Y" % chr(187))
708
709         row = col.row()
710         row.prop(con, "map_to_z_from", expand=False, text="")
711         row.label(text=" %s    Z" % chr(187))
712
713         split = layout.split()
714
715         col = split.column()
716         col.label(text="Destination:")
717         col.row().prop(con, "map_to", expand=True)
718
719         split = layout.split()
720         ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
721
722         col = split.column()
723         col.label(text="X:")
724
725         sub = col.column(align=True)
726         sub.prop(con, "to_min_x" + ext, text="Min")
727         sub.prop(con, "to_max_x" + ext, text="Max")
728
729         col = split.column()
730         col.label(text="Y:")
731
732         sub = col.column(align=True)
733         sub.prop(con, "to_min_y" + ext, text="Min")
734         sub.prop(con, "to_max_y" + ext, text="Max")
735
736         col = split.column()
737         col.label(text="Z:")
738
739         sub = col.column(align=True)
740         sub.prop(con, "to_min_z" + ext, text="Min")
741         sub.prop(con, "to_max_z" + ext, text="Max")
742
743         self.space_template(layout, con)
744
745     def SHRINKWRAP(self, context, layout, con):
746         self.target_template(layout, con, False)
747
748         layout.prop(con, "distance")
749         layout.prop(con, "shrinkwrap_type")
750
751         if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
752             layout.prop(con, "wrap_mode", text="Snap Mode")
753
754         if con.shrinkwrap_type == 'PROJECT':
755             row = layout.row(align=True)
756             row.prop(con, "project_axis", expand=True)
757             split = layout.split(factor=0.4)
758             split.label(text="Axis Space:")
759             rowsub = split.row()
760             rowsub.prop(con, "project_axis_space", text="")
761             split = layout.split(factor=0.4)
762             split.label(text="Face Culling:")
763             rowsub = split.row()
764             rowsub.prop(con, "cull_face", expand=True)
765             row = layout.row()
766             row.prop(con, "use_project_opposite")
767             rowsub = row.row()
768             rowsub.active = con.use_project_opposite and con.cull_face != 'OFF'
769             rowsub.prop(con, "use_invert_cull")
770             layout.prop(con, "project_limit")
771
772         if con.shrinkwrap_type in {'PROJECT', 'NEAREST_SURFACE', 'TARGET_PROJECT'}:
773             layout.prop(con, "use_track_normal")
774
775             row = layout.row(align=True)
776             row.active = con.use_track_normal
777             row.prop(con, "track_axis", expand=True)
778
779     def DAMPED_TRACK(self, context, layout, con):
780         self.target_template(layout, con)
781
782         row = layout.row()
783         row.label(text="To:")
784         row.prop(con, "track_axis", expand=True)
785
786     def SPLINE_IK(self, context, layout, con):
787         self.target_template(layout, con)
788
789         col = layout.column()
790         col.label(text="Spline Fitting:")
791         col.prop(con, "chain_count")
792         col.prop(con, "use_even_divisions")
793         col.prop(con, "use_chain_offset")
794
795         col = layout.column()
796         col.label(text="Chain Scaling:")
797         col.prop(con, "use_y_stretch")
798         col.prop(con, "use_curve_radius")
799
800         layout.prop(con, "xz_scale_mode")
801
802         if con.xz_scale_mode == 'VOLUME_PRESERVE':
803             layout.prop(con, "bulge", text="Volume Variation")
804             split = layout.split()
805             col = split.column(align=True)
806             col.prop(con, "use_bulge_min", text="Volume Min")
807             sub = col.column()
808             sub.active = con.use_bulge_min
809             sub.prop(con, "bulge_min", text="")
810             col = split.column(align=True)
811             col.prop(con, "use_bulge_max", text="Volume Max")
812             sub = col.column()
813             sub.active = con.use_bulge_max
814             sub.prop(con, "bulge_max", text="")
815             col = layout.column()
816             col.active = con.use_bulge_min or con.use_bulge_max
817             col.prop(con, "bulge_smooth", text="Smooth")
818
819     def PIVOT(self, context, layout, con):
820         self.target_template(layout, con)
821
822         if con.target:
823             col = layout.column()
824             col.prop(con, "offset", text="Pivot Offset")
825         else:
826             col = layout.column()
827             col.prop(con, "use_relative_location")
828             if con.use_relative_location:
829                 col.prop(con, "offset", text="Relative Pivot Point")
830             else:
831                 col.prop(con, "offset", text="Absolute Pivot Point")
832
833         col = layout.column()
834         col.prop(con, "rotation_range", text="Pivot When")
835
836     @staticmethod
837     def _getConstraintClip(context, con):
838         if not con.use_active_clip:
839             return con.clip
840         else:
841             return context.scene.active_clip
842
843     def FOLLOW_TRACK(self, context, layout, con):
844         clip = self._getConstraintClip(context, con)
845
846         row = layout.row()
847         row.prop(con, "use_active_clip")
848         row.prop(con, "use_3d_position")
849
850         sub = row.column()
851         sub.active = not con.use_3d_position
852         sub.prop(con, "use_undistorted_position")
853
854         col = layout.column()
855
856         if not con.use_active_clip:
857             col.prop(con, "clip")
858
859         row = col.row()
860         row.prop(con, "frame_method", expand=True)
861
862         if clip:
863             tracking = clip.tracking
864
865             col.prop_search(con, "object", tracking, "objects", icon='OBJECT_DATA')
866
867             tracking_object = tracking.objects.get(con.object, tracking.objects[0])
868
869             col.prop_search(con, "track", tracking_object, "tracks", icon='ANIM_DATA')
870
871         col.prop(con, "camera")
872
873         row = col.row()
874         row.active = not con.use_3d_position
875         row.prop(con, "depth_object")
876
877         layout.operator("clip.constraint_to_fcurve")
878
879     def CAMERA_SOLVER(self, context, layout, con):
880         layout.prop(con, "use_active_clip")
881
882         if not con.use_active_clip:
883             layout.prop(con, "clip")
884
885         layout.operator("clip.constraint_to_fcurve")
886
887     def OBJECT_SOLVER(self, context, layout, con):
888         clip = self._getConstraintClip(context, con)
889
890         layout.prop(con, "use_active_clip")
891
892         if not con.use_active_clip:
893             layout.prop(con, "clip")
894
895         if clip:
896             layout.prop_search(con, "object", clip.tracking, "objects", icon='OBJECT_DATA')
897
898         layout.prop(con, "camera")
899
900         row = layout.row()
901         row.operator("constraint.objectsolver_set_inverse")
902         row.operator("constraint.objectsolver_clear_inverse")
903
904         layout.operator("clip.constraint_to_fcurve")
905
906     def TRANSFORM_CACHE(self, context, layout, con):
907         layout.label(text="Cache File Properties:")
908         box = layout.box()
909         box.template_cache_file(con, "cache_file")
910
911         cache_file = con.cache_file
912
913         layout.label(text="Constraint Properties:")
914         box = layout.box()
915
916         if cache_file is not None:
917             box.prop_search(con, "object_path", cache_file, "object_paths")
918
919     def SCRIPT(self, context, layout, con):
920         layout.label(text="Blender 2.6 doesn't support python constraints yet")
921
922     def ARMATURE(self, context, layout, con):
923         topcol = layout.column()
924         topcol.use_property_split = True
925         topcol.operator("constraint.add_target", text="Add Target Bone")
926
927         if not con.targets:
928             box = topcol.box()
929             box.label(text="No target bones were added", icon='ERROR')
930
931         for i, tgt in enumerate(con.targets):
932             box = topcol.box()
933
934             has_target = tgt.target is not None
935
936             header = box.row()
937             header.use_property_split = False
938
939             split = header.split(factor=0.45, align=True)
940             split.prop(tgt, "target", text="")
941
942             row = split.row(align=True)
943             row.active = has_target
944             if has_target:
945                 row.prop_search(tgt, "subtarget", tgt.target.data, "bones", text="")
946             else:
947                 row.prop(tgt, "subtarget", text="", icon='BONE_DATA')
948
949             header.operator("constraint.remove_target", text="", icon='REMOVE').index = i
950
951             col = box.column()
952             col.active = has_target and tgt.subtarget != ""
953             col.prop(tgt, "weight", slider=True)
954
955         topcol.operator("constraint.normalize_target_weights")
956         topcol.prop(con, "use_deform_preserve_volume")
957         topcol.prop(con, "use_bone_envelopes")
958
959         if context.pose_bone:
960             topcol.prop(con, "use_current_location")
961
962
963 class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
964     bl_label = "Object Constraints"
965     bl_context = "constraint"
966     bl_options = {'HIDE_HEADER'}
967
968     @classmethod
969     def poll(cls, context):
970         return (context.object)
971
972     def draw(self, context):
973         layout = self.layout
974
975         obj = context.object
976
977         if obj.type == 'ARMATURE' and obj.mode == 'POSE':
978             box = layout.box()
979             box.alert = True  # XXX: this should apply to the box background
980             box.label(icon='INFO', text="Constraints for active bone do not live here")
981             box.operator("wm.properties_context_change", icon='CONSTRAINT_BONE',
982                          text="Go to Bone Constraints tab...").context = 'BONE_CONSTRAINT'
983         else:
984             layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
985
986         for con in obj.constraints:
987             self.draw_constraint(context, con)
988
989
990 class BONE_PT_constraints(ConstraintButtonsPanel, Panel):
991     bl_label = "Bone Constraints"
992     bl_context = "bone_constraint"
993     bl_options = {'HIDE_HEADER'}
994
995     @classmethod
996     def poll(cls, context):
997         return (context.pose_bone)
998
999     def draw(self, context):
1000         layout = self.layout
1001
1002         layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")
1003
1004         for con in context.pose_bone.constraints:
1005             self.draw_constraint(context, con)
1006
1007
1008 classes = (
1009     OBJECT_PT_constraints,
1010     BONE_PT_constraints,
1011 )
1012
1013 if __name__ == "__main__":  # only for live edit.
1014     from bpy.utils import register_class
1015     for cls in classes:
1016         register_class(cls)