1 # ##### BEGIN GPL LICENSE BLOCK #####
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 # ##### END GPL LICENSE BLOCK #####
24 class ConstraintButtonsPanel(bpy.types.Panel):
25 bl_space_type = 'PROPERTIES'
26 bl_region_type = 'WINDOW'
27 bl_context = "constraint"
29 def draw_constraint(self, context, con):
32 box = layout.template_constraint(con)
33 col2 = context.region.width > narrowui
36 # match enum type to our functions, avoids a lookup table.
37 getattr(self, con.type)(context, box, con, col2)
39 # show/key buttons here are most likely obsolete now, with
40 # keyframing functionality being part of every button
41 if con.type not in ('RIGID_BODY_JOINT', 'SPLINE_IK', 'NULL'):
42 box.itemR(con, "influence")
44 def space_template(self, layout, con, col2, target=True, owner=True):
47 split = layout.split(percentage=0.2)
50 split.itemL(text="Space:")
57 row.itemR(con, "target_space", text="")
61 row.itemL(icon='ICON_ARROW_LEFTRIGHT')
65 row.itemR(con, "owner_space", text="")
67 def target_template(self, layout, con, col2, subtargets=True):
69 layout.itemR(con, "target") # XXX limiting settings for only 'curves' or some type of object
71 layout.itemR(con, "target", text="")
73 if con.target and subtargets:
74 if con.target.type == 'ARMATURE':
76 layout.item_pointerR(con, "subtarget", con.target.data, "bones", text="Bone")
78 layout.item_pointerR(con, "subtarget", con.target.data, "bones", text="")
80 if con.type == 'COPY_LOCATION':
82 row.itemL(text="Head/Tail:")
83 row.itemR(con, "head_tail", text="")
84 elif con.target.type in ('MESH', 'LATTICE'):
85 layout.item_pointerR(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
87 def ik_template(self, layout, con, col2):
89 layout.itemR(con, "pole_target")
91 if con.pole_target and con.pole_target.type == 'ARMATURE':
92 layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
97 row.itemR(con, "pole_angle")
99 split = layout.split(percentage=0.33)
101 col.itemR(con, "tail")
102 col.itemR(con, "stretch")
105 col.itemR(con, "chain_length")
106 col.itemR(con, "targetless")
108 def CHILD_OF(self, context, layout, con, col2):
109 self.target_template(layout, con, col2)
111 split = layout.split()
114 col.itemL(text="Location:")
115 col.itemR(con, "locationx", text="X")
116 col.itemR(con, "locationy", text="Y")
117 col.itemR(con, "locationz", text="Z")
120 col.itemL(text="Rotation:")
121 col.itemR(con, "rotationx", text="X")
122 col.itemR(con, "rotationy", text="Y")
123 col.itemR(con, "rotationz", text="Z")
126 col.itemL(text="Scale:")
127 col.itemR(con, "sizex", text="X")
128 col.itemR(con, "sizey", text="Y")
129 col.itemR(con, "sizez", text="Z")
131 split = layout.split()
134 col.itemO("constraint.childof_set_inverse")
138 col.itemO("constraint.childof_clear_inverse")
140 def TRACK_TO(self, context, layout, con, col2):
141 self.target_template(layout, con, col2)
145 row.itemL(text="To:")
146 row.itemR(con, "track", expand=True)
148 split = layout.split()
151 col.itemR(con, "up", text="Up")
155 col.itemR(con, "target_z")
157 self.space_template(layout, con, col2)
159 def IK(self, context, layout, con, col2):
160 if context.object.pose.ik_solver == "ITASC":
161 layout.itemR(con, "ik_type")
162 getattr(self, 'IK_' + con.ik_type)(context, layout, con)
164 # Legacy IK constraint
165 self.target_template(layout, con, col2)
167 layout.itemR(con, "pole_target")
169 layout.itemR(con, "pole_target", text="")
170 if con.pole_target and con.pole_target.type == 'ARMATURE':
172 layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
174 layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="")
178 row.itemR(con, "pole_angle")
182 split = layout.split()
184 col.itemR(con, "iterations")
185 col.itemR(con, "chain_length")
187 col.itemL(text="Weight:")
188 col.itemR(con, "weight", text="Position", slider=True)
190 sub.active = con.rotation
191 sub.itemR(con, "orient_weight", text="Rotation", slider=True)
195 col.itemR(con, "tail")
196 col.itemR(con, "stretch")
198 col.itemR(con, "targetless")
199 col.itemR(con, "rotation")
201 def IK_COPY_POSE(self, context, layout, con, col2):
202 self.target_template(layout, con, col2)
203 self.ik_template(layout, con, col2)
206 row.itemL(text="Axis Ref:")
207 row.itemR(con, "axis_reference", expand=True)
208 split = layout.split(percentage=0.33)
209 split.row().itemR(con, "position")
211 row.itemR(con, "weight", text="Weight", slider=True)
212 row.active = con.position
213 split = layout.split(percentage=0.33)
215 row.itemL(text="Lock:")
217 row.itemR(con, "pos_lock_x", text="X")
218 row.itemR(con, "pos_lock_y", text="Y")
219 row.itemR(con, "pos_lock_z", text="Z")
220 split.active = con.position
222 split = layout.split(percentage=0.33)
223 split.row().itemR(con, "rotation")
225 row.itemR(con, "orient_weight", text="Weight", slider=True)
226 row.active = con.rotation
227 split = layout.split(percentage=0.33)
229 row.itemL(text="Lock:")
231 row.itemR(con, "rot_lock_x", text="X")
232 row.itemR(con, "rot_lock_y", text="Y")
233 row.itemR(con, "rot_lock_z", text="Z")
234 split.active = con.rotation
236 def IK_DISTANCE(self, context, layout, con, col2):
237 self.target_template(layout, con, col2)
238 self.ik_template(layout, con, col2)
240 layout.itemR(con, "limit_mode")
242 row.itemR(con, "weight", text="Weight", slider=True)
243 row.itemR(con, "distance", text="Distance", slider=True)
245 def FOLLOW_PATH(self, context, layout, con, col2):
246 self.target_template(layout, con, col2)
248 split = layout.split()
251 col.itemR(con, "use_curve_follow")
252 col.itemR(con, "use_curve_radius")
256 col.itemR(con, "use_fixed_position")
257 if con.use_fixed_position:
258 col.itemR(con, "offset_factor", text="Offset")
260 col.itemR(con, "offset")
264 row.itemL(text="Forward:")
265 row.itemR(con, "forward", expand=True)
268 row.itemR(con, "up", text="Up")
272 def LIMIT_ROTATION(self, context, layout, con, col2):
274 split = layout.split()
276 col = split.column(align=True)
277 col.itemR(con, "use_limit_x")
279 sub.active = con.use_limit_x
280 sub.itemR(con, "minimum_x", text="Min")
281 sub.itemR(con, "maximum_x", text="Max")
284 col = split.column(align=True)
285 col.itemR(con, "use_limit_y")
287 sub.active = con.use_limit_y
288 sub.itemR(con, "minimum_y", text="Min")
289 sub.itemR(con, "maximum_y", text="Max")
292 col = split.column(align=True)
293 col.itemR(con, "use_limit_z")
295 sub.active = con.use_limit_z
296 sub.itemR(con, "minimum_z", text="Min")
297 sub.itemR(con, "maximum_z", text="Max")
300 row.itemR(con, "limit_transform")
306 row.itemL(text="Convert:")
307 row.itemR(con, "owner_space", text="")
309 def LIMIT_LOCATION(self, context, layout, con, col2):
310 split = layout.split()
313 col.itemR(con, "use_minimum_x")
315 sub.active = con.use_minimum_x
316 sub.itemR(con, "minimum_x", text="")
317 col.itemR(con, "use_maximum_x")
319 sub.active = con.use_maximum_x
320 sub.itemR(con, "maximum_x", text="")
324 col.itemR(con, "use_minimum_y")
326 sub.active = con.use_minimum_y
327 sub.itemR(con, "minimum_y", text="")
328 col.itemR(con, "use_maximum_y")
330 sub.active = con.use_maximum_y
331 sub.itemR(con, "maximum_y", text="")
335 col.itemR(con, "use_minimum_z")
337 sub.active = con.use_minimum_z
338 sub.itemR(con, "minimum_z", text="")
339 col.itemR(con, "use_maximum_z")
341 sub.active = con.use_maximum_z
342 sub.itemR(con, "maximum_z", text="")
345 row.itemR(con, "limit_transform")
351 row.itemL(text="Convert:")
352 row.itemR(con, "owner_space", text="")
354 def LIMIT_SCALE(self, context, layout, con, col2):
355 split = layout.split()
358 col.itemR(con, "use_minimum_x")
360 sub.active = con.use_minimum_x
361 sub.itemR(con, "minimum_x", text="")
362 col.itemR(con, "use_maximum_x")
364 sub.active = con.use_maximum_x
365 sub.itemR(con, "maximum_x", text="")
369 col.itemR(con, "use_minimum_y")
371 sub.active = con.use_minimum_y
372 sub.itemR(con, "minimum_y", text="")
373 col.itemR(con, "use_maximum_y")
375 sub.active = con.use_maximum_y
376 sub.itemR(con, "maximum_y", text="")
380 col.itemR(con, "use_minimum_z")
382 sub.active = con.use_minimum_z
383 sub.itemR(con, "minimum_z", text="")
384 col.itemR(con, "use_maximum_z")
386 sub.active = con.use_maximum_z
387 sub.itemR(con, "maximum_z", text="")
390 row.itemR(con, "limit_transform")
396 row.itemL(text="Convert:")
397 row.itemR(con, "owner_space", text="")
399 def COPY_ROTATION(self, context, layout, con, col2):
400 self.target_template(layout, con, col2)
402 split = layout.split()
405 col.itemR(con, "rotate_like_x", text="X")
407 sub.active = con.rotate_like_x
408 sub.itemR(con, "invert_x", text="Invert")
411 col.itemR(con, "rotate_like_y", text="Y")
413 sub.active = con.rotate_like_y
414 sub.itemR(con, "invert_y", text="Invert")
417 col.itemR(con, "rotate_like_z", text="Z")
419 sub.active = con.rotate_like_z
420 sub.itemR(con, "invert_z", text="Invert")
422 layout.itemR(con, "offset")
424 self.space_template(layout, con, col2)
426 def COPY_LOCATION(self, context, layout, con, col2):
427 self.target_template(layout, con, col2)
429 split = layout.split()
432 col.itemR(con, "locate_like_x", text="X")
434 sub.active = con.locate_like_x
435 sub.itemR(con, "invert_x", text="Invert")
438 col.itemR(con, "locate_like_y", text="Y")
440 sub.active = con.locate_like_y
441 sub.itemR(con, "invert_y", text="Invert")
444 col.itemR(con, "locate_like_z", text="Z")
446 sub.active = con.locate_like_z
447 sub.itemR(con, "invert_z", text="Invert")
449 layout.itemR(con, "offset")
451 self.space_template(layout, con, col2)
453 def COPY_SCALE(self, context, layout, con, col2):
454 self.target_template(layout, con, col2)
456 row = layout.row(align=True)
457 row.itemR(con, "size_like_x", text="X")
458 row.itemR(con, "size_like_y", text="Y")
459 row.itemR(con, "size_like_z", text="Z")
461 layout.itemR(con, "offset")
463 self.space_template(layout, con, col2)
465 #def SCRIPT(self, context, layout, con):
467 def ACTION(self, context, layout, con, col2):
468 self.target_template(layout, con, col2)
471 layout.itemR(con, "action")
473 layout.itemR(con, "action", text="")
476 layout.itemR(con, "transform_channel")
478 layout.itemR(con, "transform_channel", text="")
480 split = layout.split()
482 col = split.column(align=True)
483 col.itemL(text="Action Length:")
484 col.itemR(con, "start_frame", text="Start")
485 col.itemR(con, "end_frame", text="End")
488 col = split.column(align=True)
489 col.itemL(text="Target Range:")
490 col.itemR(con, "minimum", text="Min")
491 col.itemR(con, "maximum", text="Max")
495 row.itemL(text="Convert:")
496 row.itemR(con, "target_space", text="")
498 def LOCKED_TRACK(self, context, layout, con, col2):
499 self.target_template(layout, con, col2)
503 row.itemL(text="To:")
504 row.itemR(con, "track", expand=True)
508 row.itemL(text="Lock:")
509 row.itemR(con, "locked", expand=True)
511 def LIMIT_DISTANCE(self, context, layout, con, col2):
512 self.target_template(layout, con, col2)
514 col = layout.column(align=True)
515 col.itemR(con, "distance")
516 col.itemO("constraint.limitdistance_reset")
519 row.itemL(text="Clamp Region:")
520 row.itemR(con, "limit_mode", text="")
522 def STRETCH_TO(self, context, layout, con, col2):
523 self.target_template(layout, con, col2)
525 split = layout.split()
528 col.itemR(con, "original_length", text="Rest Length")
532 col.itemO("constraint.stretchto_reset", text="Reset")
534 col = layout.column()
535 col.itemR(con, "bulge", text="Volume Variation")
539 row.itemL(text="Volume:")
540 row.itemR(con, "volume", expand=True)
543 row.itemL(text="Plane:")
544 row.itemR(con, "keep_axis", expand=True)
546 def FLOOR(self, context, layout, con, col2):
547 self.target_template(layout, con, col2)
549 split = layout.split()
552 col.itemR(con, "sticky")
556 col.itemR(con, "use_rotation")
558 layout.itemR(con, "offset")
562 row.itemL(text="Min/Max:")
563 row.itemR(con, "floor_location", expand=True)
565 def RIGID_BODY_JOINT(self, context, layout, con, col2):
566 self.target_template(layout, con, col2)
569 layout.itemR(con, "pivot_type")
571 layout.itemR(con, "pivot_type", text="")
573 layout.itemR(con, "child")
575 layout.itemR(con, "child", text="")
577 split = layout.split()
580 col.itemR(con, "disable_linked_collision", text="No Collision")
584 col.itemR(con, "draw_pivot", text="Display Pivot")
586 split = layout.split()
588 col = split.column(align=True)
589 col.itemL(text="Pivot:")
590 col.itemR(con, "pivot_x", text="X")
591 col.itemR(con, "pivot_y", text="Y")
592 col.itemR(con, "pivot_z", text="Z")
595 col = split.column(align=True)
596 col.itemL(text="Axis:")
597 col.itemR(con, "axis_x", text="X")
598 col.itemR(con, "axis_y", text="Y")
599 col.itemR(con, "axis_z", text="Z")
601 #Missing: Limit arrays (not wrapped in RNA yet)
603 def CLAMP_TO(self, context, layout, con, col2):
604 self.target_template(layout, con, col2)
608 row.itemL(text="Main Axis:")
609 row.itemR(con, "main_axis", expand=True)
612 row.itemR(con, "cyclic")
614 def TRANSFORM(self, context, layout, con, col2):
615 self.target_template(layout, con, col2)
617 layout.itemR(con, "extrapolate_motion", text="Extrapolate")
619 col = layout.column()
620 col.row().itemL(text="Source:")
621 col.row().itemR(con, "map_from", expand=True)
623 split = layout.split()
625 sub = split.column(align=True)
627 sub.itemR(con, "from_min_x", text="Min")
628 sub.itemR(con, "from_max_x", text="Max")
631 sub = split.column(align=True)
633 sub.itemR(con, "from_min_y", text="Min")
634 sub.itemR(con, "from_max_y", text="Max")
637 sub = split.column(align=True)
639 sub.itemR(con, "from_min_z", text="Min")
640 sub.itemR(con, "from_max_z", text="Max")
642 split = layout.split()
645 col.itemL(text="Destination:")
646 col.row().itemR(con, "map_to", expand=True)
648 split = layout.split()
652 col.row().itemR(con, "map_to_x_from", expand=True)
654 sub = col.column(align=True)
655 sub.itemR(con, "to_min_x", text="Min")
656 sub.itemR(con, "to_max_x", text="Max")
661 col.row().itemR(con, "map_to_y_from", expand=True)
663 sub = col.column(align=True)
664 sub.itemR(con, "to_min_y", text="Min")
665 sub.itemR(con, "to_max_y", text="Max")
670 col.row().itemR(con, "map_to_z_from", expand=True)
672 sub = col.column(align=True)
673 sub.itemR(con, "to_min_z", text="Min")
674 sub.itemR(con, "to_max_z", text="Max")
676 self.space_template(layout, con, col2)
678 def SHRINKWRAP(self, context, layout, con, col2):
679 self.target_template(layout, con, col2)
681 layout.itemR(con, "distance")
682 layout.itemR(con, "shrinkwrap_type")
684 if con.shrinkwrap_type == 'PROJECT':
685 row = layout.row(align=True)
686 row.itemR(con, "axis_x")
687 row.itemR(con, "axis_y")
688 row.itemR(con, "axis_z")
690 def DAMPED_TRACK(self, context, layout, con, col2):
691 self.target_template(layout, con, col2)
695 row.itemL(text="To:")
696 row.itemR(con, "track", expand=True)
698 def SPLINE_IK(self, context, layout, con, col2):
699 self.target_template(layout, con, col2)
701 col = layout.column()
702 col.itemL(text="Spline Fitting:")
703 col.itemR(con, "chain_length")
704 col.itemR(con, "even_divisions")
705 col.itemR(con, "chain_offset")
707 col = layout.column()
708 col.itemL(text="Chain Scaling:")
709 col.itemR(con, "y_scaling")
711 col.itemR(con, "xz_scaling_mode")
713 col.itemR(con, "xz_scaling_mode", text="")
716 class OBJECT_PT_constraints(ConstraintButtonsPanel):
717 bl_label = "Object Constraints"
718 bl_context = "constraint"
720 def poll(self, context):
721 return (context.object)
723 def draw(self, context):
726 col2 = context.region.width > narrowui
729 row.item_menu_enumO("object.constraint_add", "type")
733 for con in ob.constraints:
734 self.draw_constraint(context, con)
737 class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
738 bl_label = "Inverse Kinematics"
739 bl_default_closed = True
740 bl_context = "bone_constraint"
742 def poll(self, context):
747 pchan = ob.pose.bones[bone.name]
752 def draw(self, context):
757 pchan = ob.pose.bones[bone.name]
758 col2 = context.region.width > narrowui
761 row.itemR(ob.pose, "ik_solver")
763 split = layout.split(percentage=0.25)
764 split.itemR(pchan, "ik_dof_x", text="X")
766 row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
767 row.active = pchan.ik_dof_x
770 split = layout.split(percentage=0.25)
773 sub = layout.column(align=True)
774 sub.itemR(pchan, "ik_limit_x", text="Limit")
775 sub.active = pchan.ik_dof_x
777 sub = split.row(align=True)
778 sub.itemR(pchan, "ik_min_x", text="")
779 sub.itemR(pchan, "ik_max_x", text="")
780 sub.active = pchan.ik_dof_x and pchan.ik_limit_x
782 split = layout.split(percentage=0.25)
783 split.itemR(pchan, "ik_dof_y", text="Y")
785 row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
786 row.active = pchan.ik_dof_y
789 split = layout.split(percentage=0.25)
792 sub = layout.column(align=True)
793 sub.itemR(pchan, "ik_limit_y", text="Limit")
794 sub.active = pchan.ik_dof_y
796 sub = split.row(align=True)
797 sub.itemR(pchan, "ik_min_y", text="")
798 sub.itemR(pchan, "ik_max_y", text="")
799 sub.active = pchan.ik_dof_y and pchan.ik_limit_y
801 split = layout.split(percentage=0.25)
802 split.itemR(pchan, "ik_dof_z", text="Z")
804 sub.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
805 sub.active = pchan.ik_dof_z
808 split = layout.split(percentage=0.25)
811 sub = layout.column(align=True)
812 sub.itemR(pchan, "ik_limit_z", text="Limit")
813 sub.active = pchan.ik_dof_z
815 sub = split.row(align=True)
816 sub.itemR(pchan, "ik_min_z", text="")
817 sub.itemR(pchan, "ik_max_z", text="")
818 sub.active = pchan.ik_dof_z and pchan.ik_limit_z
819 split = layout.split()
820 split.itemR(pchan, "ik_stretch", text="Stretch", slider=True)
824 if ob.pose.ik_solver == 'ITASC':
825 split = layout.split()
827 col.itemR(pchan, "ik_rot_control", text="Control Rotation")
830 col.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
833 #row.itemR(pchan, "ik_lin_control", text="Joint Size")
834 #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
837 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
838 bl_label = "iTaSC parameters"
839 bl_default_closed = True
840 bl_context = "bone_constraint"
842 def poll(self, context):
847 pchan = ob.pose.bones[bone.name]
848 return pchan.has_ik and ob.pose.ik_solver == 'ITASC' and ob.pose.ik_param
852 def draw(self, context):
856 itasc = ob.pose.ik_param
857 col2 = context.region.width > narrowui
859 layout.itemR(itasc, "mode", expand=True)
860 simulation = itasc.mode == 'SIMULATION'
862 layout.itemL(text="Reiteration:")
863 layout.itemR(itasc, "reiteration", expand=True)
865 split = layout.split()
866 split.active = not simulation or itasc.reiteration != 'NEVER'
868 col.itemR(itasc, "precision")
872 col.itemR(itasc, "num_iter")
876 layout.itemR(itasc, "auto_step")
879 row.itemR(itasc, "min_step", text="Min")
880 row.itemR(itasc, "max_step", text="Max")
882 row.itemR(itasc, "num_step")
884 layout.itemR(itasc, "solver")
886 layout.itemR(itasc, "feedback")
887 layout.itemR(itasc, "max_velocity")
888 if itasc.solver == 'DLS':
890 row.itemR(itasc, "dampmax", text="Damp", slider=True)
891 row.itemR(itasc, "dampeps", text="Eps", slider=True)
894 class BONE_PT_constraints(ConstraintButtonsPanel):
895 bl_label = "Bone Constraints"
896 bl_context = "bone_constraint"
898 def poll(self, context):
900 return (ob and ob.type == 'ARMATURE' and context.bone)
902 def draw(self, context):
906 pchan = ob.pose.bones[context.bone.name]
907 col2 = context.region.width > narrowui
910 row.item_menu_enumO("pose.constraint_add", "type")
914 for con in pchan.constraints:
915 self.draw_constraint(context, con)
917 bpy.types.register(OBJECT_PT_constraints)
918 bpy.types.register(BONE_PT_iksolver_itasc)
919 bpy.types.register(BONE_PT_inverse_kinematics)
920 bpy.types.register(BONE_PT_constraints)