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