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