1cc0073fbca9e3005e6906077e6112857051fc28
[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', '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, "owner_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         row = layout.row()
602         row.itemR(con, "chain_length")
603         # TODO: add the various options this constraint has...
604
605
606 class OBJECT_PT_constraints(ConstraintButtonsPanel):
607     bl_label = "Constraints"
608     bl_context = "constraint"
609
610     def poll(self, context):
611         return (context.object)
612
613     def draw(self, context):
614         layout = self.layout
615         ob = context.object
616
617         row = layout.row()
618         row.item_menu_enumO("object.constraint_add", "type")
619         row.itemL()
620
621         for con in ob.constraints:
622             self.draw_constraint(context, con)
623
624
625 class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
626     bl_label = "Inverse Kinematics"
627     bl_default_closed = True
628     bl_context = "bone_constraint"
629
630     def poll(self, context):
631         ob = context.object
632         bone = context.bone
633
634         if ob and bone:
635             pchan = ob.pose.pose_channels[bone.name]
636             return pchan.has_ik
637
638         return False
639
640     def draw(self, context):
641         layout = self.layout
642
643         ob = context.object
644         bone = context.bone
645         pchan = ob.pose.pose_channels[bone.name]
646
647         row = layout.row()
648         row.itemR(ob.pose, "ik_solver")
649
650         split = layout.split(percentage=0.25)
651         split.itemR(pchan, "ik_dof_x", text="X")
652         row = split.row()
653         row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
654         row.active = pchan.ik_dof_x
655
656         split = layout.split(percentage=0.25)
657         row = split.row()
658         row.itemR(pchan, "ik_limit_x", text="Limit")
659         row.active = pchan.ik_dof_x
660         row = split.row(align=True)
661         row.itemR(pchan, "ik_min_x", text="")
662         row.itemR(pchan, "ik_max_x", text="")
663         row.active = pchan.ik_dof_x and pchan.ik_limit_x
664
665         split = layout.split(percentage=0.25)
666         split.itemR(pchan, "ik_dof_y", text="Y")
667         row = split.row()
668         row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
669         row.active = pchan.ik_dof_y
670
671         split = layout.split(percentage=0.25)
672         row = split.row()
673         row.itemR(pchan, "ik_limit_y", text="Limit")
674         row.active = pchan.ik_dof_y
675         row = split.row(align=True)
676         row.itemR(pchan, "ik_min_y", text="")
677         row.itemR(pchan, "ik_max_y", text="")
678         row.active = pchan.ik_dof_y and pchan.ik_limit_y
679
680         split = layout.split(percentage=0.25)
681         split.itemR(pchan, "ik_dof_z", text="Z")
682         row = split.row()
683         row.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
684         row.active = pchan.ik_dof_z
685
686         split = layout.split(percentage=0.25)
687         row = split.row()
688         row.itemR(pchan, "ik_limit_z", text="Limit")
689         row.active = pchan.ik_dof_z
690         row = split.row(align=True)
691         row.itemR(pchan, "ik_min_z", text="")
692         row.itemR(pchan, "ik_max_z", text="")
693         row.active = pchan.ik_dof_z and pchan.ik_limit_z
694         split = layout.split()
695         split.itemR(pchan, "ik_stretch", text="Stretch", slider=True)
696         split.itemL()
697
698         if ob.pose.ik_solver == "ITASC":
699             row = layout.row()
700             row.itemR(pchan, "ik_rot_control", text="Control Rotation")
701             row.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
702             # not supported yet
703             #row = layout.row()
704             #row.itemR(pchan, "ik_lin_control", text="Joint Size")
705             #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
706
707
708 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
709     bl_label = "iTaSC parameters"
710     bl_default_closed = True
711     bl_context = "bone_constraint"
712
713     def poll(self, context):
714         ob = context.object
715         bone = context.bone
716
717         if ob and bone:
718             pchan = ob.pose.pose_channels[bone.name]
719             return pchan.has_ik and ob.pose.ik_solver == "ITASC" and ob.pose.ik_param
720
721         return False
722
723     def draw(self, context):
724         layout = self.layout
725
726         ob = context.object
727         itasc = ob.pose.ik_param
728
729         layout.itemR(itasc, "mode", expand=True)
730         simulation = itasc.mode == "SIMULATION"
731         if simulation:
732             layout.itemL(text="Reiteration:")
733             layout.itemR(itasc, "reiteration", expand=True)
734
735         flow = layout.column_flow()
736         flow.itemR(itasc, "precision", text="Prec")
737         flow.itemR(itasc, "num_iter", text="Iter")
738         flow.active = not simulation or itasc.reiteration != "NEVER"
739
740         if simulation:
741             layout.itemR(itasc, "auto_step")
742             row = layout.row()
743             if itasc.auto_step:
744                 row.itemR(itasc, "min_step", text="Min")
745                 row.itemR(itasc, "max_step", text="Max")
746             else:
747                 row.itemR(itasc, "num_step")
748
749         layout.itemR(itasc, "solver")
750         if simulation:
751             layout.itemR(itasc, "feedback")
752             layout.itemR(itasc, "max_velocity")
753         if itasc.solver == "DLS":
754             row = layout.row()
755             row.itemR(itasc, "dampmax", text="Damp", slider=True)
756             row.itemR(itasc, "dampeps", text="Eps", slider=True)
757
758
759 class BONE_PT_constraints(ConstraintButtonsPanel):
760     bl_label = "Constraints"
761     bl_context = "bone_constraint"
762
763     def poll(self, context):
764         ob = context.object
765         return (ob and ob.type == 'ARMATURE' and context.bone)
766
767     def draw(self, context):
768         layout = self.layout
769
770         ob = context.object
771         pchan = ob.pose.pose_channels[context.bone.name]
772
773         row = layout.row()
774         row.item_menu_enumO("pose.constraint_add", "type")
775         row.itemL()
776
777         for con in pchan.constraints:
778             self.draw_constraint(context, con)
779
780 bpy.types.register(OBJECT_PT_constraints)
781 bpy.types.register(BONE_PT_iksolver_itasc)
782 bpy.types.register(BONE_PT_inverse_kinematics)
783 bpy.types.register(BONE_PT_constraints)