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