550b202f588716e1770dd40c287b6b8af672caf9
[blender.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21
22
23 class ConstraintButtonsPanel(bpy.types.Panel):
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             # show/key buttons here are most likely obsolete now, with
38             # keyframing functionality being part of every button
39             if con.type not in ('RIGID_BODY_JOINT', 'SPLINE_IK', 'NULL'):
40                 box.itemR(con, "influence")
41
42     def space_template(self, layout, con, target=True, owner=True):
43         if target or owner:
44             row = layout.row()
45
46             row.itemL(text="Convert:")
47
48             if target:
49                 row.itemR(con, "target_space", text="")
50
51             if target and owner:
52                 row.itemL(icon='ICON_ARROW_LEFTRIGHT')
53
54             if owner:
55                 row.itemR(con, "owner_space", text="")
56
57     def target_template(self, layout, con, subtargets=True):
58         layout.itemR(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.item_pointerR(con, "subtarget", con.target.data, "bones", text="Bone")
63
64                 if con.type == 'COPY_LOCATION':
65                     row = layout.row()
66                     row.itemL(text="Head/Tail:")
67                     row.itemR(con, "head_tail", text="")
68             elif con.target.type in ('MESH', 'LATTICE'):
69                 layout.item_pointerR(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
70
71     def ik_template(self, layout, con):
72         # only used for iTaSC
73         layout.itemR(con, "pole_target")
74
75         if con.pole_target and con.pole_target.type == 'ARMATURE':
76             layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
77
78         if con.pole_target:
79             row = layout.row()
80             row.itemL()
81             row.itemR(con, "pole_angle")
82
83         split = layout.split(percentage=0.33)
84         col = split.column()
85         col.itemR(con, "tail")
86         col.itemR(con, "stretch")
87
88         col = split.column()
89         col.itemR(con, "chain_length")
90         col.itemR(con, "targetless")
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.itemL(text="Location:")
99         col.itemR(con, "locationx", text="X")
100         col.itemR(con, "locationy", text="Y")
101         col.itemR(con, "locationz", text="Z")
102
103         col = split.column()
104         col.itemL(text="Rotation:")
105         col.itemR(con, "rotationx", text="X")
106         col.itemR(con, "rotationy", text="Y")
107         col.itemR(con, "rotationz", text="Z")
108
109         col = split.column()
110         col.itemL(text="Scale:")
111         col.itemR(con, "sizex", text="X")
112         col.itemR(con, "sizey", text="Y")
113         col.itemR(con, "sizez", text="Z")
114
115         row = layout.row()
116         row.itemO("constraint.childof_set_inverse")
117         row.itemO("constraint.childof_clear_inverse")
118
119     def TRACK_TO(self, context, layout, con):
120         self.target_template(layout, con)
121
122         row = layout.row()
123         row.itemL(text="To:")
124         row.itemR(con, "track", expand=True)
125
126         row = layout.row()
127         #row.itemR(con, "up", text="Up", expand=True) # XXX: up and expand don't play nice together
128         row.itemR(con, "up", text="Up")
129         row.itemR(con, "target_z")
130
131         self.space_template(layout, con)
132
133     def IK(self, context, layout, con):
134         if context.object.pose.ik_solver == "ITASC":
135             layout.itemR(con, "ik_type")
136             getattr(self, "IK_" + con.ik_type)(context, layout, con)
137         else:
138             # Legacy IK constraint
139             self.target_template(layout, con)
140             layout.itemR(con, "pole_target")
141
142             if con.pole_target and con.pole_target.type == 'ARMATURE':
143                 layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
144
145             if con.pole_target:
146                 row = layout.row()
147                 row.itemL()
148                 row.itemR(con, "pole_angle")
149
150             split = layout.split()
151             col = split.column()
152             col.itemR(con, "tail")
153             col.itemR(con, "stretch")
154
155             col = split.column()
156             col.itemR(con, "iterations")
157             col.itemR(con, "chain_length")
158
159             split = layout.split()
160             col = split.column()
161             col.itemL()
162             col.itemR(con, "targetless")
163             col.itemR(con, "rotation")
164
165             col = split.column()
166             col.itemL(text="Weight:")
167             col.itemR(con, "weight", text="Position", slider=True)
168             sub = col.column()
169             sub.active = con.rotation
170             sub.itemR(con, "orient_weight", text="Rotation", slider=True)
171
172     def IK_COPY_POSE(self, context, layout, con):
173         self.target_template(layout, con)
174         self.ik_template(layout, con)
175
176         row = layout.row()
177         row.itemL(text="Axis Ref:")
178         row.itemR(con, "axis_reference", expand=True)
179         split = layout.split(percentage=0.33)
180         split.row().itemR(con, "position")
181         row = split.row()
182         row.itemR(con, "weight", text="Weight", slider=True)
183         row.active = con.position
184         split = layout.split(percentage=0.33)
185         row = split.row()
186         row.itemL(text="Lock:")
187         row = split.row()
188         row.itemR(con, "pos_lock_x", text="X")
189         row.itemR(con, "pos_lock_y", text="Y")
190         row.itemR(con, "pos_lock_z", text="Z")
191         split.active = con.position
192
193         split = layout.split(percentage=0.33)
194         split.row().itemR(con, "rotation")
195         row = split.row()
196         row.itemR(con, "orient_weight", text="Weight", slider=True)
197         row.active = con.rotation
198         split = layout.split(percentage=0.33)
199         row = split.row()
200         row.itemL(text="Lock:")
201         row = split.row()
202         row.itemR(con, "rot_lock_x", text="X")
203         row.itemR(con, "rot_lock_y", text="Y")
204         row.itemR(con, "rot_lock_z", text="Z")
205         split.active = con.rotation
206
207     def IK_DISTANCE(self, context, layout, con):
208         self.target_template(layout, con)
209         self.ik_template(layout, con)
210
211         layout.itemR(con, "limit_mode")
212         row = layout.row()
213         row.itemR(con, "weight", text="Weight", slider=True)
214         row.itemR(con, "distance", text="Distance", slider=True)
215
216     def FOLLOW_PATH(self, context, layout, con):
217         self.target_template(layout, con)
218
219         split = layout.split()
220
221         col = split.column()
222         col.itemR(con, "use_curve_follow")
223         col.itemR(con, "use_curve_radius")
224
225         col = split.column()
226         col.itemR(con, "use_fixed_position")
227         if con.use_fixed_position:
228             col.itemR(con, "offset_factor", text="Offset")
229         else:
230             col.itemR(con, "offset")
231
232         row = layout.row()
233         row.itemL(text="Forward:")
234         row.itemR(con, "forward", expand=True)
235
236         row = layout.row()
237         row.itemR(con, "up", text="Up")
238         row.itemL()
239
240     def LIMIT_ROTATION(self, context, layout, con):
241
242         split = layout.split()
243
244         col = split.column()
245         col.itemR(con, "use_limit_x")
246         sub = col.column()
247         sub.active = con.use_limit_x
248         sub.itemR(con, "minimum_x", text="Min")
249         sub.itemR(con, "maximum_x", text="Max")
250
251         col = split.column()
252         col.itemR(con, "use_limit_y")
253         sub = col.column()
254         sub.active = con.use_limit_y
255         sub.itemR(con, "minimum_y", text="Min")
256         sub.itemR(con, "maximum_y", text="Max")
257
258         col = split.column()
259         col.itemR(con, "use_limit_z")
260         sub = col.column()
261         sub.active = con.use_limit_z
262         sub.itemR(con, "minimum_z", text="Min")
263         sub.itemR(con, "maximum_z", text="Max")
264
265         row = layout.row()
266         row.itemR(con, "limit_transform")
267         row.itemL()
268
269         row = layout.row()
270         row.itemL(text="Convert:")
271         row.itemR(con, "owner_space", text="")
272
273     def LIMIT_LOCATION(self, context, layout, con):
274         split = layout.split()
275
276         col = split.column()
277         col.itemR(con, "use_minimum_x")
278         sub = col.column()
279         sub.active = con.use_minimum_x
280         sub.itemR(con, "minimum_x", text="")
281         col.itemR(con, "use_maximum_x")
282         sub = col.column()
283         sub.active = con.use_maximum_x
284         sub.itemR(con, "maximum_x", text="")
285
286         col = split.column()
287         col.itemR(con, "use_minimum_y")
288         sub = col.column()
289         sub.active = con.use_minimum_y
290         sub.itemR(con, "minimum_y", text="")
291         col.itemR(con, "use_maximum_y")
292         sub = col.column()
293         sub.active = con.use_maximum_y
294         sub.itemR(con, "maximum_y", text="")
295
296         col = split.column()
297         col.itemR(con, "use_minimum_z")
298         sub = col.column()
299         sub.active = con.use_minimum_z
300         sub.itemR(con, "minimum_z", text="")
301         col.itemR(con, "use_maximum_z")
302         sub = col.column()
303         sub.active = con.use_maximum_z
304         sub.itemR(con, "maximum_z", text="")
305
306         row = layout.row()
307         row.itemR(con, "limit_transform")
308         row.itemL()
309
310         row = layout.row()
311         row.itemL(text="Convert:")
312         row.itemR(con, "owner_space", text="")
313
314     def LIMIT_SCALE(self, context, layout, con):
315         split = layout.split()
316
317         col = split.column()
318         col.itemR(con, "use_minimum_x")
319         sub = col.column()
320         sub.active = con.use_minimum_x
321         sub.itemR(con, "minimum_x", text="")
322         col.itemR(con, "use_maximum_x")
323         sub = col.column()
324         sub.active = con.use_maximum_x
325         sub.itemR(con, "maximum_x", text="")
326
327         col = split.column()
328         col.itemR(con, "use_minimum_y")
329         sub = col.column()
330         sub.active = con.use_minimum_y
331         sub.itemR(con, "minimum_y", text="")
332         col.itemR(con, "use_maximum_y")
333         sub = col.column()
334         sub.active = con.use_maximum_y
335         sub.itemR(con, "maximum_y", text="")
336
337         col = split.column()
338         col.itemR(con, "use_minimum_z")
339         sub = col.column()
340         sub.active = con.use_minimum_z
341         sub.itemR(con, "minimum_z", text="")
342         col.itemR(con, "use_maximum_z")
343         sub = col.column()
344         sub.active = con.use_maximum_z
345         sub.itemR(con, "maximum_z", text="")
346
347         row = layout.row()
348         row.itemR(con, "limit_transform")
349         row.itemL()
350
351         row = layout.row()
352         row.itemL(text="Convert:")
353         row.itemR(con, "owner_space", text="")
354
355     def COPY_ROTATION(self, context, layout, con):
356         self.target_template(layout, con)
357
358         split = layout.split()
359
360         col = split.column()
361         col.itemR(con, "rotate_like_x", text="X")
362         sub = col.column()
363         sub.active = con.rotate_like_x
364         sub.itemR(con, "invert_x", text="Invert")
365
366         col = split.column()
367         col.itemR(con, "rotate_like_y", text="Y")
368         sub = col.column()
369         sub.active = con.rotate_like_y
370         sub.itemR(con, "invert_y", text="Invert")
371
372         col = split.column()
373         col.itemR(con, "rotate_like_z", text="Z")
374         sub = col.column()
375         sub.active = con.rotate_like_z
376         sub.itemR(con, "invert_z", text="Invert")
377
378         layout.itemR(con, "offset")
379
380         self.space_template(layout, con)
381
382     def COPY_LOCATION(self, context, layout, con):
383         self.target_template(layout, con)
384
385         split = layout.split()
386
387         col = split.column()
388         col.itemR(con, "locate_like_x", text="X")
389         sub = col.column()
390         sub.active = con.locate_like_x
391         sub.itemR(con, "invert_x", text="Invert")
392
393         col = split.column()
394         col.itemR(con, "locate_like_y", text="Y")
395         sub = col.column()
396         sub.active = con.locate_like_y
397         sub.itemR(con, "invert_y", text="Invert")
398
399         col = split.column()
400         col.itemR(con, "locate_like_z", text="Z")
401         sub = col.column()
402         sub.active = con.locate_like_z
403         sub.itemR(con, "invert_z", text="Invert")
404
405         layout.itemR(con, "offset")
406
407         self.space_template(layout, con)
408
409     def COPY_SCALE(self, context, layout, con):
410         self.target_template(layout, con)
411
412         row = layout.row(align=True)
413         row.itemR(con, "size_like_x", text="X")
414         row.itemR(con, "size_like_y", text="Y")
415         row.itemR(con, "size_like_z", text="Z")
416
417         layout.itemR(con, "offset")
418
419         self.space_template(layout, con)
420
421     #def SCRIPT(self, context, layout, con):
422
423     def ACTION(self, context, layout, con):
424         self.target_template(layout, con)
425
426         layout.itemR(con, "action")
427         layout.itemR(con, "transform_channel")
428
429         split = layout.split()
430
431         col = split.column(align=True)
432         col.itemR(con, "start_frame", text="Start")
433         col.itemR(con, "end_frame", text="End")
434
435         col = split.column(align=True)
436         col.itemR(con, "minimum", text="Min")
437         col.itemR(con, "maximum", text="Max")
438
439         row = layout.row()
440         row.itemL(text="Convert:")
441         row.itemR(con, "target_space", text="")
442
443     def LOCKED_TRACK(self, context, layout, con):
444         self.target_template(layout, con)
445
446         row = layout.row()
447         row.itemL(text="To:")
448         row.itemR(con, "track", expand=True)
449
450         row = layout.row()
451         row.itemL(text="Lock:")
452         row.itemR(con, "locked", expand=True)
453
454     def LIMIT_DISTANCE(self, context, layout, con):
455         self.target_template(layout, con)
456
457         col = layout.column(align=True)
458         col.itemR(con, "distance")
459         col.itemO("constraint.limitdistance_reset")
460
461         row = layout.row()
462         row.itemL(text="Clamp Region:")
463         row.itemR(con, "limit_mode", text="")
464
465     def STRETCH_TO(self, context, layout, con):
466         self.target_template(layout, con)
467
468         row = layout.row()
469         row.itemR(con, "original_length", text="Rest Length")
470         row.itemO("constraint.stretchto_reset", text="Reset")
471
472         col = layout.column()
473         col.itemR(con, "bulge", text="Volume Variation")
474
475         row = layout.row()
476         row.itemL(text="Volume:")
477         row.itemR(con, "volume", expand=True)
478         row.itemL(text="Plane:")
479         row.itemR(con, "keep_axis", expand=True)
480
481     def FLOOR(self, context, layout, con):
482         self.target_template(layout, con)
483
484         row = layout.row()
485         row.itemR(con, "sticky")
486         row.itemR(con, "use_rotation")
487
488         layout.itemR(con, "offset")
489
490         row = layout.row()
491         row.itemL(text="Min/Max:")
492         row.itemR(con, "floor_location", expand=True)
493
494     def RIGID_BODY_JOINT(self, context, layout, con):
495         self.target_template(layout, con)
496
497         layout.itemR(con, "pivot_type")
498         layout.itemR(con, "child")
499
500         row = layout.row()
501         row.itemR(con, "disable_linked_collision", text="No Collision")
502         row.itemR(con, "draw_pivot", text="Display Pivot")
503
504         split = layout.split()
505
506         col = split.column(align=True)
507         col.itemL(text="Pivot:")
508         col.itemR(con, "pivot_x", text="X")
509         col.itemR(con, "pivot_y", text="Y")
510         col.itemR(con, "pivot_z", text="Z")
511
512         col = split.column(align=True)
513         col.itemL(text="Axis:")
514         col.itemR(con, "axis_x", text="X")
515         col.itemR(con, "axis_y", text="Y")
516         col.itemR(con, "axis_z", text="Z")
517
518         #Missing: Limit arrays (not wrapped in RNA yet)
519
520     def CLAMP_TO(self, context, layout, con):
521         self.target_template(layout, con)
522
523         row = layout.row()
524         row.itemL(text="Main Axis:")
525         row.itemR(con, "main_axis", expand=True)
526
527         row = layout.row()
528         row.itemR(con, "cyclic")
529
530     def TRANSFORM(self, context, layout, con):
531         self.target_template(layout, con)
532
533         layout.itemR(con, "extrapolate_motion", text="Extrapolate")
534
535         split = layout.split()
536
537         col = split.column()
538         col.itemL(text="Source:")
539         col.row().itemR(con, "map_from", expand=True)
540
541         sub = col.row(align=True)
542         sub.itemL(text="X:")
543         sub.itemR(con, "from_min_x", text="")
544         sub.itemR(con, "from_max_x", text="")
545
546         sub = col.row(align=True)
547         sub.itemL(text="Y:")
548         sub.itemR(con, "from_min_y", text="")
549         sub.itemR(con, "from_max_y", text="")
550
551         sub = col.row(align=True)
552         sub.itemL(text="Z:")
553         sub.itemR(con, "from_min_z", text="")
554         sub.itemR(con, "from_max_z", text="")
555
556         split = layout.split()
557
558         col = split.column()
559         col.itemL(text="Destination:")
560         col.row().itemR(con, "map_to", expand=True)
561
562         sub = col.row(align=True)
563         sub.itemR(con, "map_to_x_from", text="")
564         sub.itemR(con, "to_min_x", text="")
565         sub.itemR(con, "to_max_x", text="")
566
567         sub = col.row(align=True)
568         sub.itemR(con, "map_to_y_from", text="")
569         sub.itemR(con, "to_min_y", text="")
570         sub.itemR(con, "to_max_y", text="")
571
572         sub = col.row(align=True)
573         sub.itemR(con, "map_to_z_from", text="")
574         sub.itemR(con, "to_min_z", text="")
575         sub.itemR(con, "to_max_z", text="")
576
577         self.space_template(layout, con)
578
579     def SHRINKWRAP(self, context, layout, con):
580         self.target_template(layout, con)
581
582         layout.itemR(con, "distance")
583         layout.itemR(con, "shrinkwrap_type")
584
585         if con.shrinkwrap_type == 'PROJECT':
586             row = layout.row(align=True)
587             row.itemR(con, "axis_x")
588             row.itemR(con, "axis_y")
589             row.itemR(con, "axis_z")
590
591     def DAMPED_TRACK(self, context, layout, con):
592         self.target_template(layout, con)
593
594         row = layout.row()
595         row.itemL(text="To:")
596         row.itemR(con, "track", expand=True)
597
598     def SPLINE_IK(self, context, layout, con):
599         self.target_template(layout, con)
600
601         col = layout.column()
602         col.itemL(text="Spline Fitting:")
603         col.itemR(con, "chain_length")
604         col.itemR(con, "even_divisions")
605         #col.itemR(con, "affect_root") # XXX: this is not that useful yet
606
607         col = layout.column()
608         col.itemL(text="Chain Scaling:")
609         col.itemR(con, "keep_max_length")
610         col.itemR(con, "xz_scaling_mode")
611
612
613 class OBJECT_PT_constraints(ConstraintButtonsPanel):
614     bl_label = "Object Constraints"
615     bl_context = "constraint"
616
617     def poll(self, context):
618         return (context.object)
619
620     def draw(self, context):
621         layout = self.layout
622         ob = context.object
623
624         row = layout.row()
625         row.item_menu_enumO("object.constraint_add", "type")
626         row.itemL()
627
628         for con in ob.constraints:
629             self.draw_constraint(context, con)
630
631
632 class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
633     bl_label = "Inverse Kinematics"
634     bl_default_closed = True
635     bl_context = "bone_constraint"
636
637     def poll(self, context):
638         ob = context.object
639         bone = context.bone
640
641         if ob and bone:
642             pchan = ob.pose.pose_channels[bone.name]
643             return pchan.has_ik
644
645         return False
646
647     def draw(self, context):
648         layout = self.layout
649
650         ob = context.object
651         bone = context.bone
652         pchan = ob.pose.pose_channels[bone.name]
653
654         row = layout.row()
655         row.itemR(ob.pose, "ik_solver")
656
657         split = layout.split(percentage=0.25)
658         split.itemR(pchan, "ik_dof_x", text="X")
659         row = split.row()
660         row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
661         row.active = pchan.ik_dof_x
662
663         split = layout.split(percentage=0.25)
664         row = split.row()
665         row.itemR(pchan, "ik_limit_x", text="Limit")
666         row.active = pchan.ik_dof_x
667         row = split.row(align=True)
668         row.itemR(pchan, "ik_min_x", text="")
669         row.itemR(pchan, "ik_max_x", text="")
670         row.active = pchan.ik_dof_x and pchan.ik_limit_x
671
672         split = layout.split(percentage=0.25)
673         split.itemR(pchan, "ik_dof_y", text="Y")
674         row = split.row()
675         row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
676         row.active = pchan.ik_dof_y
677
678         split = layout.split(percentage=0.25)
679         row = split.row()
680         row.itemR(pchan, "ik_limit_y", text="Limit")
681         row.active = pchan.ik_dof_y
682         row = split.row(align=True)
683         row.itemR(pchan, "ik_min_y", text="")
684         row.itemR(pchan, "ik_max_y", text="")
685         row.active = pchan.ik_dof_y and pchan.ik_limit_y
686
687         split = layout.split(percentage=0.25)
688         split.itemR(pchan, "ik_dof_z", text="Z")
689         row = split.row()
690         row.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
691         row.active = pchan.ik_dof_z
692
693         split = layout.split(percentage=0.25)
694         row = split.row()
695         row.itemR(pchan, "ik_limit_z", text="Limit")
696         row.active = pchan.ik_dof_z
697         row = split.row(align=True)
698         row.itemR(pchan, "ik_min_z", text="")
699         row.itemR(pchan, "ik_max_z", text="")
700         row.active = pchan.ik_dof_z and pchan.ik_limit_z
701         split = layout.split()
702         split.itemR(pchan, "ik_stretch", text="Stretch", slider=True)
703         split.itemL()
704
705         if ob.pose.ik_solver == "ITASC":
706             row = layout.row()
707             row.itemR(pchan, "ik_rot_control", text="Control Rotation")
708             row.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
709             # not supported yet
710             #row = layout.row()
711             #row.itemR(pchan, "ik_lin_control", text="Joint Size")
712             #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
713
714
715 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
716     bl_label = "iTaSC parameters"
717     bl_default_closed = True
718     bl_context = "bone_constraint"
719
720     def poll(self, context):
721         ob = context.object
722         bone = context.bone
723
724         if ob and bone:
725             pchan = ob.pose.pose_channels[bone.name]
726             return pchan.has_ik and ob.pose.ik_solver == "ITASC" and ob.pose.ik_param
727
728         return False
729
730     def draw(self, context):
731         layout = self.layout
732
733         ob = context.object
734         itasc = ob.pose.ik_param
735
736         layout.itemR(itasc, "mode", expand=True)
737         simulation = itasc.mode == "SIMULATION"
738         if simulation:
739             layout.itemL(text="Reiteration:")
740             layout.itemR(itasc, "reiteration", expand=True)
741
742         flow = layout.column_flow()
743         flow.itemR(itasc, "precision", text="Prec")
744         flow.itemR(itasc, "num_iter", text="Iter")
745         flow.active = not simulation or itasc.reiteration != "NEVER"
746
747         if simulation:
748             layout.itemR(itasc, "auto_step")
749             row = layout.row()
750             if itasc.auto_step:
751                 row.itemR(itasc, "min_step", text="Min")
752                 row.itemR(itasc, "max_step", text="Max")
753             else:
754                 row.itemR(itasc, "num_step")
755
756         layout.itemR(itasc, "solver")
757         if simulation:
758             layout.itemR(itasc, "feedback")
759             layout.itemR(itasc, "max_velocity")
760         if itasc.solver == "DLS":
761             row = layout.row()
762             row.itemR(itasc, "dampmax", text="Damp", slider=True)
763             row.itemR(itasc, "dampeps", text="Eps", slider=True)
764
765
766 class BONE_PT_constraints(ConstraintButtonsPanel):
767     bl_label = "Bone Constraints"
768     bl_context = "bone_constraint"
769
770     def poll(self, context):
771         ob = context.object
772         return (ob and ob.type == 'ARMATURE' and context.bone)
773
774     def draw(self, context):
775         layout = self.layout
776
777         ob = context.object
778         pchan = ob.pose.pose_channels[context.bone.name]
779
780         row = layout.row()
781         row.item_menu_enumO("pose.constraint_add", "type")
782         row.itemL()
783
784         for con in pchan.constraints:
785             self.draw_constraint(context, con)
786
787 bpy.types.register(OBJECT_PT_constraints)
788 bpy.types.register(BONE_PT_iksolver_itasc)
789 bpy.types.register(BONE_PT_inverse_kinematics)
790 bpy.types.register(BONE_PT_constraints)