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