59eb8e40e7800f4fc0a354755f90b2fee6cb96a7
[blender-staging.git] / release / scripts / ui / properties_object_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
22
23 class ConstraintButtonsPanel():
24     bl_space_type = 'PROPERTIES'
25     bl_region_type = 'WINDOW'
26     bl_context = "constraint"
27
28     def draw_constraint(self, context, con):
29         layout = self.layout
30
31         box = layout.template_constraint(con)
32
33         if box:
34             # match enum type to our functions, avoids a lookup table.
35             getattr(self, con.type)(context, box, con)
36
37             if con.type not in ('RIGID_BODY_JOINT', 'NULL'):
38                 box.prop(con, "influence")
39
40     def space_template(self, layout, con, target=True, owner=True):
41         if target or owner:
42
43             split = layout.split(percentage=0.2)
44
45             split.label(text="Space:")
46             row = split.row()
47
48             if target:
49                 row.prop(con, "target_space", text="")
50
51             if target and owner:
52                 row.label(icon='ARROW_LEFTRIGHT')
53
54             if owner:
55                 row.prop(con, "owner_space", text="")
56
57     def target_template(self, layout, con, subtargets=True):
58         layout.prop(con, "target") # XXX limiting settings for only 'curves' or some type of object
59
60         if con.target and subtargets:
61             if con.target.type == 'ARMATURE':
62                 layout.prop_object(con, "subtarget", con.target.data, "bones", text="Bone")
63
64                 if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO', 'PIVOT'):
65                     row = layout.row()
66                     row.label(text="Head/Tail:")
67                     row.prop(con, "head_tail", text="")
68             elif con.target.type in ('MESH', 'LATTICE'):
69                 layout.prop_object(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
70
71     def ik_template(self, layout, con):
72         # only used for iTaSC
73         layout.prop(con, "pole_target")
74
75         if con.pole_target and con.pole_target.type == 'ARMATURE':
76             layout.prop_object(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
77
78         if con.pole_target:
79             row = layout.row()
80             row.label()
81             row.prop(con, "pole_angle")
82
83         split = layout.split(percentage=0.33)
84         col = split.column()
85         col.prop(con, "use_tail")
86         col.prop(con, "use_stretch")
87
88         col = split.column()
89         col.prop(con, "chain_length")
90         col.prop(con, "use_target")
91
92     def CHILD_OF(self, context, layout, con):
93         self.target_template(layout, con)
94
95         split = layout.split()
96
97         col = split.column()
98         col.label(text="Location:")
99         col.prop(con, "use_location_x", text="X")
100         col.prop(con, "use_location_y", text="Y")
101         col.prop(con, "use_location_z", text="Z")
102
103         col = split.column()
104         col.label(text="Rotation:")
105         col.prop(con, "use_rotation_x", text="X")
106         col.prop(con, "use_rotation_y", text="Y")
107         col.prop(con, "use_rotation_z", text="Z")
108
109         col = split.column()
110         col.label(text="Scale:")
111         col.prop(con, "use_scale_x", text="X")
112         col.prop(con, "use_scale_y", text="Y")
113         col.prop(con, "use_scale_z", text="Z")
114
115         split = layout.split()
116
117         col = split.column()
118         col.operator("constraint.childof_set_inverse")
119
120         col = split.column()
121         col.operator("constraint.childof_clear_inverse")
122
123     def TRACK_TO(self, context, layout, con):
124         self.target_template(layout, con)
125
126         row = layout.row()
127         row.label(text="To:")
128         row.prop(con, "track", expand=True)
129
130         split = layout.split()
131
132         col = split.column()
133         col.prop(con, "up", text="Up")
134
135         col = split.column()
136         col.prop(con, "target_z")
137
138         self.space_template(layout, con)
139
140     def IK(self, context, layout, con):
141         if context.object.pose.ik_solver == "ITASC":
142             layout.prop(con, "ik_type")
143             getattr(self, 'IK_' + con.ik_type)(context, layout, con)
144         else:
145             # Legacy IK constraint
146             self.target_template(layout, con)
147             layout.prop(con, "pole_target")
148
149             if con.pole_target and con.pole_target.type == 'ARMATURE':
150                 layout.prop_object(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
151
152             if con.pole_target:
153                 row = layout.row()
154                 row.prop(con, "pole_angle")
155                 row.label()
156
157             split = layout.split()
158             col = split.column()
159             col.prop(con, "iterations")
160             col.prop(con, "chain_length")
161
162             col.label(text="Weight:")
163             col.prop(con, "weight", text="Position", slider=True)
164             sub = col.column()
165             sub.active = con.use_rotation
166             sub.prop(con, "orient_weight", text="Rotation", slider=True)
167
168             col = split.column()
169             col.prop(con, "use_tail")
170             col.prop(con, "use_stretch")
171             col.separator()
172             col.prop(con, "use_target")
173             col.prop(con, "use_rotation")
174
175     def IK_COPY_POSE(self, context, layout, con):
176         self.target_template(layout, con)
177         self.ik_template(layout, con)
178
179         row = layout.row()
180         row.label(text="Axis Ref:")
181         row.prop(con, "axis_reference", expand=True)
182         split = layout.split(percentage=0.33)
183         split.row().prop(con, "use_position")
184         row = split.row()
185         row.prop(con, "weight", text="Weight", slider=True)
186         row.active = con.use_position
187         split = layout.split(percentage=0.33)
188         row = split.row()
189         row.label(text="Lock:")
190         row = split.row()
191         row.prop(con, "pos_lock_x", text="X")
192         row.prop(con, "pos_lock_y", text="Y")
193         row.prop(con, "pos_lock_z", text="Z")
194         split.active = con.use_position
195
196         split = layout.split(percentage=0.33)
197         split.row().prop(con, "use_rotation")
198         row = split.row()
199         row.prop(con, "orient_weight", text="Weight", slider=True)
200         row.active = con.use_rotation
201         split = layout.split(percentage=0.33)
202         row = split.row()
203         row.label(text="Lock:")
204         row = split.row()
205         row.prop(con, "rot_lock_x", text="X")
206         row.prop(con, "rot_lock_y", text="Y")
207         row.prop(con, "rot_lock_z", text="Z")
208         split.active = con.use_rotation
209
210     def IK_DISTANCE(self, context, layout, con):
211         self.target_template(layout, con)
212         self.ik_template(layout, con)
213
214         layout.prop(con, "limit_mode")
215         row = layout.row()
216         row.prop(con, "weight", text="Weight", slider=True)
217         row.prop(con, "distance", text="Distance", slider=True)
218
219     def FOLLOW_PATH(self, context, layout, con):
220         self.target_template(layout, con)
221
222         split = layout.split()
223
224         col = split.column()
225         col.prop(con, "use_curve_follow")
226         col.prop(con, "use_curve_radius")
227
228         col = split.column()
229         col.prop(con, "use_fixed_position")
230         if con.use_fixed_position:
231             col.prop(con, "offset_factor", text="Offset")
232         else:
233             col.prop(con, "offset")
234
235         row = layout.row()
236         row.label(text="Forward:")
237         row.prop(con, "forward", expand=True)
238
239         row = layout.row()
240         row.prop(con, "up", text="Up")
241         row.label()
242
243     def LIMIT_ROTATION(self, context, layout, con):
244
245         split = layout.split()
246
247         col = split.column(align=True)
248         col.prop(con, "use_limit_x")
249         sub = col.column()
250         sub.active = con.use_limit_x
251         sub.prop(con, "minimum_x", text="Min")
252         sub.prop(con, "maximum_x", text="Max")
253
254         col = split.column(align=True)
255         col.prop(con, "use_limit_y")
256         sub = col.column()
257         sub.active = con.use_limit_y
258         sub.prop(con, "minimum_y", text="Min")
259         sub.prop(con, "maximum_y", text="Max")
260
261         col = split.column(align=True)
262         col.prop(con, "use_limit_z")
263         sub = col.column()
264         sub.active = con.use_limit_z
265         sub.prop(con, "minimum_z", text="Min")
266         sub.prop(con, "maximum_z", text="Max")
267
268         row = layout.row()
269         row.prop(con, "limit_transform")
270         row.label()
271
272         row = layout.row()
273         row.label(text="Convert:")
274         row.prop(con, "owner_space", text="")
275
276     def LIMIT_LOCATION(self, context, layout, con):
277         split = layout.split()
278
279         col = split.column()
280         col.prop(con, "use_minimum_x")
281         sub = col.column()
282         sub.active = con.use_minimum_x
283         sub.prop(con, "minimum_x", text="")
284         col.prop(con, "use_maximum_x")
285         sub = col.column()
286         sub.active = con.use_maximum_x
287         sub.prop(con, "maximum_x", text="")
288
289         col = split.column()
290         col.prop(con, "use_minimum_y")
291         sub = col.column()
292         sub.active = con.use_minimum_y
293         sub.prop(con, "minimum_y", text="")
294         col.prop(con, "use_maximum_y")
295         sub = col.column()
296         sub.active = con.use_maximum_y
297         sub.prop(con, "maximum_y", text="")
298
299         col = split.column()
300         col.prop(con, "use_minimum_z")
301         sub = col.column()
302         sub.active = con.use_minimum_z
303         sub.prop(con, "minimum_z", text="")
304         col.prop(con, "use_maximum_z")
305         sub = col.column()
306         sub.active = con.use_maximum_z
307         sub.prop(con, "maximum_z", text="")
308
309         row = layout.row()
310         row.prop(con, "limit_transform")
311         row.label()
312
313         row = layout.row()
314         row.label(text="Convert:")
315         row.prop(con, "owner_space", text="")
316
317     def LIMIT_SCALE(self, context, layout, con):
318         split = layout.split()
319
320         col = split.column()
321         col.prop(con, "use_minimum_x")
322         sub = col.column()
323         sub.active = con.use_minimum_x
324         sub.prop(con, "minimum_x", text="")
325         col.prop(con, "use_maximum_x")
326         sub = col.column()
327         sub.active = con.use_maximum_x
328         sub.prop(con, "maximum_x", text="")
329
330         col = split.column()
331         col.prop(con, "use_minimum_y")
332         sub = col.column()
333         sub.active = con.use_minimum_y
334         sub.prop(con, "minimum_y", text="")
335         col.prop(con, "use_maximum_y")
336         sub = col.column()
337         sub.active = con.use_maximum_y
338         sub.prop(con, "maximum_y", text="")
339
340         col = split.column()
341         col.prop(con, "use_minimum_z")
342         sub = col.column()
343         sub.active = con.use_minimum_z
344         sub.prop(con, "minimum_z", text="")
345         col.prop(con, "use_maximum_z")
346         sub = col.column()
347         sub.active = con.use_maximum_z
348         sub.prop(con, "maximum_z", text="")
349
350         row = layout.row()
351         row.prop(con, "limit_transform")
352         row.label()
353
354         row = layout.row()
355         row.label(text="Convert:")
356         row.prop(con, "owner_space", text="")
357
358     def COPY_ROTATION(self, context, layout, con):
359         self.target_template(layout, con)
360
361         split = layout.split()
362
363         col = split.column()
364         col.prop(con, "use_x", text="X")
365         sub = col.column()
366         sub.active = con.use_x
367         sub.prop(con, "invert_x", text="Invert")
368
369         col = split.column()
370         col.prop(con, "use_y", text="Y")
371         sub = col.column()
372         sub.active = con.use_y
373         sub.prop(con, "invert_y", text="Invert")
374
375         col = split.column()
376         col.prop(con, "use_z", text="Z")
377         sub = col.column()
378         sub.active = con.use_z
379         sub.prop(con, "invert_z", text="Invert")
380
381         layout.prop(con, "use_offset")
382
383         self.space_template(layout, con)
384
385     def COPY_LOCATION(self, context, layout, con):
386         self.target_template(layout, con)
387
388         split = layout.split()
389
390         col = split.column()
391         col.prop(con, "use_x", text="X")
392         sub = col.column()
393         sub.active = con.use_x
394         sub.prop(con, "invert_x", text="Invert")
395
396         col = split.column()
397         col.prop(con, "use_y", text="Y")
398         sub = col.column()
399         sub.active = con.use_y
400         sub.prop(con, "invert_y", text="Invert")
401
402         col = split.column()
403         col.prop(con, "use_z", text="Z")
404         sub = col.column()
405         sub.active = con.use_z
406         sub.prop(con, "invert_z", text="Invert")
407
408         layout.prop(con, "use_offset")
409
410         self.space_template(layout, con)
411
412     def COPY_SCALE(self, context, layout, con):
413         self.target_template(layout, con)
414
415         row = layout.row(align=True)
416         row.prop(con, "use_x", text="X")
417         row.prop(con, "use_y", text="Y")
418         row.prop(con, "use_z", text="Z")
419
420         layout.prop(con, "use_offset")
421
422         self.space_template(layout, con)
423
424     def MAINTAIN_VOLUME(self, context, layout, con):
425
426         row = layout.row()
427         row.label(text="Free:")
428         row.prop(con, "axis", expand=True)
429
430         layout.prop(con, "volume")
431
432         self.space_template(layout, con)
433
434     def COPY_TRANSFORMS(self, context, layout, con):
435         self.target_template(layout, con)
436
437         self.space_template(layout, con)
438
439     #def SCRIPT(self, context, layout, con):
440
441     def ACTION(self, context, layout, con):
442         self.target_template(layout, con)
443
444         layout.prop(con, "action")
445
446         layout.prop(con, "transform_channel")
447
448         split = layout.split()
449
450         col = split.column(align=True)
451         col.label(text="Action Length:")
452         col.prop(con, "frame_start", text="Start")
453         col.prop(con, "frame_end", text="End")
454
455         col = split.column(align=True)
456         col.label(text="Target Range:")
457         col.prop(con, "minimum", text="Min")
458         col.prop(con, "maximum", text="Max")
459
460         row = layout.row()
461         row.label(text="Convert:")
462         row.prop(con, "target_space", text="")
463
464     def LOCKED_TRACK(self, context, layout, con):
465         self.target_template(layout, con)
466
467         row = layout.row()
468         row.label(text="To:")
469         row.prop(con, "track", expand=True)
470
471         row = layout.row()
472         row.label(text="Lock:")
473         row.prop(con, "lock", expand=True)
474
475     def LIMIT_DISTANCE(self, context, layout, con):
476         self.target_template(layout, con)
477
478         col = layout.column(align=True)
479         col.prop(con, "distance")
480         col.operator("constraint.limitdistance_reset")
481
482         row = layout.row()
483         row.label(text="Clamp Region:")
484         row.prop(con, "limit_mode", text="")
485
486     def STRETCH_TO(self, context, layout, con):
487         self.target_template(layout, con)
488
489         split = layout.split()
490
491         col = split.column()
492         col.prop(con, "original_length", text="Rest Length")
493
494         col = split.column()
495         col.operator("constraint.stretchto_reset", text="Reset")
496
497         col = layout.column()
498         col.prop(con, "bulge", text="Volume Variation")
499
500         row = layout.row()
501         row.label(text="Volume:")
502         row.prop(con, "volume", expand=True)
503
504         row.label(text="Plane:")
505         row.prop(con, "keep_axis", expand=True)
506
507     def FLOOR(self, context, layout, con):
508         self.target_template(layout, con)
509
510         split = layout.split()
511
512         col = split.column()
513         col.prop(con, "sticky")
514
515         col = split.column()
516         col.prop(con, "use_rotation")
517
518         layout.prop(con, "offset")
519
520         row = layout.row()
521         row.label(text="Min/Max:")
522         row.prop(con, "floor_location", expand=True)
523
524         self.space_template(layout, con)
525
526     def RIGID_BODY_JOINT(self, context, layout, con):
527         self.target_template(layout, con)
528
529         layout.prop(con, "pivot_type")
530         layout.prop(con, "child")
531
532         split = layout.split()
533
534         col = split.column()
535         col.prop(con, "use_linked_collision", text="Linked Collision")
536
537         col = split.column()
538         col.prop(con, "show_pivot", text="Display Pivot")
539
540         split = layout.split()
541
542         col = split.column(align=True)
543         col.label(text="Pivot:")
544         col.prop(con, "pivot_x", text="X")
545         col.prop(con, "pivot_y", text="Y")
546         col.prop(con, "pivot_z", text="Z")
547
548         col = split.column(align=True)
549         col.label(text="Axis:")
550         col.prop(con, "axis_x", text="X")
551         col.prop(con, "axis_y", text="Y")
552         col.prop(con, "axis_z", text="Z")
553
554         #Missing: Limit arrays (not wrapped in RNA yet)
555
556     def CLAMP_TO(self, context, layout, con):
557         self.target_template(layout, con)
558
559         row = layout.row()
560         row.label(text="Main Axis:")
561         row.prop(con, "main_axis", expand=True)
562
563         row = layout.row()
564         row.prop(con, "cyclic")
565
566     def TRANSFORM(self, context, layout, con):
567         self.target_template(layout, con)
568
569         layout.prop(con, "extrapolate_motion", text="Extrapolate")
570
571         col = layout.column()
572         col.row().label(text="Source:")
573         col.row().prop(con, "map_from", expand=True)
574
575         split = layout.split()
576
577         sub = split.column(align=True)
578         sub.label(text="X:")
579         sub.prop(con, "from_min_x", text="Min")
580         sub.prop(con, "from_max_x", text="Max")
581
582         sub = split.column(align=True)
583         sub.label(text="Y:")
584         sub.prop(con, "from_min_y", text="Min")
585         sub.prop(con, "from_max_y", text="Max")
586
587         sub = split.column(align=True)
588         sub.label(text="Z:")
589         sub.prop(con, "from_min_z", text="Min")
590         sub.prop(con, "from_max_z", text="Max")
591
592         split = layout.split()
593
594         col = split.column()
595         col.label(text="Destination:")
596         col.row().prop(con, "map_to", expand=True)
597
598         split = layout.split()
599
600         col = split.column()
601         col.label(text="X:")
602         col.row().prop(con, "map_to_x_from", expand=True)
603
604         sub = col.column(align=True)
605         sub.prop(con, "to_min_x", text="Min")
606         sub.prop(con, "to_max_x", text="Max")
607
608         col = split.column()
609         col.label(text="Y:")
610         col.row().prop(con, "map_to_y_from", expand=True)
611
612         sub = col.column(align=True)
613         sub.prop(con, "to_min_y", text="Min")
614         sub.prop(con, "to_max_y", text="Max")
615
616         col = split.column()
617         col.label(text="Z:")
618         col.row().prop(con, "map_to_z_from", expand=True)
619
620         sub = col.column(align=True)
621         sub.prop(con, "to_min_z", text="Min")
622         sub.prop(con, "to_max_z", text="Max")
623
624         self.space_template(layout, con)
625
626     def SHRINKWRAP(self, context, layout, con):
627         self.target_template(layout, con)
628
629         layout.prop(con, "distance")
630         layout.prop(con, "shrinkwrap_type")
631
632         if con.shrinkwrap_type == 'PROJECT':
633             row = layout.row(align=True)
634             row.prop(con, "use_x")
635             row.prop(con, "use_y")
636             row.prop(con, "use_z")
637
638     def DAMPED_TRACK(self, context, layout, con):
639         self.target_template(layout, con)
640
641         row = layout.row()
642         row.label(text="To:")
643         row.prop(con, "track", expand=True)
644
645     def SPLINE_IK(self, context, layout, con):
646         self.target_template(layout, con)
647
648         col = layout.column()
649         col.label(text="Spline Fitting:")
650         col.prop(con, "chain_length")
651         col.prop(con, "even_divisions")
652         col.prop(con, "chain_offset")
653
654         col = layout.column()
655         col.label(text="Chain Scaling:")
656         col.prop(con, "y_stretch")
657         col.prop(con, "xz_scaling_mode")
658         col.prop(con, "use_curve_radius")
659
660     def PIVOT(self, context, layout, con):
661         self.target_template(layout, con)
662
663         if con.target:
664             col = layout.column()
665             col.prop(con, "offset", text="Pivot Offset")
666         else:
667             col = layout.column()
668             col.prop(con, "use_relative_position")
669             if con.use_relative_position:
670                 col.prop(con, "offset", text="Relative Pivot Point")
671             else:
672                 col.prop(con, "offset", text="Absolute Pivot Point")
673
674         col = layout.column()
675         col.prop(con, "enabled_rotation_range", text="Pivot When")
676
677 class OBJECT_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
678     bl_label = "Object Constraints"
679     bl_context = "constraint"
680
681     @classmethod
682     def poll(cls, context):
683         return (context.object)
684
685     def draw(self, context):
686         layout = self.layout
687
688         ob = context.object
689
690         layout.operator_menu_enum("object.constraint_add", "type")
691
692         for con in ob.constraints:
693             self.draw_constraint(context, con)
694
695
696 class BONE_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
697     bl_label = "Bone Constraints"
698     bl_context = "bone_constraint"
699
700     @classmethod
701     def poll(cls, context):
702         return (context.pose_bone)
703
704     def draw(self, context):
705         layout = self.layout
706
707         layout.operator_menu_enum("pose.constraint_add", "type")
708
709         for con in context.pose_bone.constraints:
710             self.draw_constraint(context, con)
711
712
713 def register():
714     pass
715
716
717 def unregister():
718     pass
719
720 if __name__ == "__main__":
721     register()