python pose_channels -> bones
[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 narrowui = 180
23
24 class ConstraintButtonsPanel(bpy.types.Panel):
25     bl_space_type = 'PROPERTIES'
26     bl_region_type = 'WINDOW'
27     bl_context = "constraint"
28
29     def draw_constraint(self, context, con):
30         layout = self.layout
31
32         box = layout.template_constraint(con)
33         col2 = context.region.width > narrowui
34
35         if box:
36             # match enum type to our functions, avoids a lookup table.
37             getattr(self, con.type)(context, box, con, col2)
38
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")
43
44     def space_template(self, layout, con, col2, target=True, owner=True):
45         if target or owner:
46             
47             split = layout.split(percentage=0.2)
48
49             if col2:
50                 split.itemL(text="Space:")
51                 row = split.row()
52             else:
53                 row = layout.row()
54             
55             
56             if target:
57                 row.itemR(con, "target_space", text="")
58
59             if col2:
60                 if target and owner:
61                     row.itemL(icon='ICON_ARROW_LEFTRIGHT')
62             else:
63                 row = layout.row()
64             if owner:
65                 row.itemR(con, "owner_space", text="")
66
67     def target_template(self, layout, con, col2, subtargets=True):
68         if col2:
69             layout.itemR(con, "target") # XXX limiting settings for only 'curves' or some type of object
70         else:
71             layout.itemR(con, "target", text="")
72
73         if con.target and subtargets:
74             if con.target.type == 'ARMATURE':
75                 if col2:
76                     layout.item_pointerR(con, "subtarget", con.target.data, "bones", text="Bone")
77                 else:
78                     layout.item_pointerR(con, "subtarget", con.target.data, "bones", text="")
79
80                 if con.type == 'COPY_LOCATION':
81                     row = layout.row()
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")
86
87     def ik_template(self, layout, con, col2):
88         # only used for iTaSC
89         layout.itemR(con, "pole_target")
90
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")
93
94         if con.pole_target:
95             row = layout.row()
96             row.itemL()
97             row.itemR(con, "pole_angle")
98
99         split = layout.split(percentage=0.33)
100         col = split.column()
101         col.itemR(con, "tail")
102         col.itemR(con, "stretch")
103
104         col = split.column()
105         col.itemR(con, "chain_length")
106         col.itemR(con, "targetless")
107
108     def CHILD_OF(self, context, layout, con, col2):
109         self.target_template(layout, con, col2)
110
111         split = layout.split()
112
113         col = split.column()
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")
118
119         col = split.column()
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")
124
125         col = split.column()
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")
130
131         split = layout.split()
132
133         col = split.column()
134         col.itemO("constraint.childof_set_inverse")
135         
136         if col2:
137             col = split.column()
138         col.itemO("constraint.childof_clear_inverse")
139
140     def TRACK_TO(self, context, layout, con, col2):
141         self.target_template(layout, con, col2)
142
143         row = layout.row()
144         if col2:
145             row.itemL(text="To:")
146         row.itemR(con, "track", expand=True)
147
148         split = layout.split()
149
150         col = split.column()
151         col.itemR(con, "up", text="Up")
152         
153         if col2:
154             col = split.column()
155         col.itemR(con, "target_z")
156
157         self.space_template(layout, con, col2)
158
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)
163         else:
164             # Legacy IK constraint
165             self.target_template(layout, con, col2)
166             if col2:
167                 layout.itemR(con, "pole_target")
168             else:
169                 layout.itemR(con, "pole_target", text="")
170             if con.pole_target and con.pole_target.type == 'ARMATURE':
171                 if col2:
172                     layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
173                 else:
174                     layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="")
175
176             if con.pole_target:
177                 row = layout.row()
178                 row.itemR(con, "pole_angle")
179                 if col2:
180                     row.itemL()
181
182             split = layout.split()
183             col = split.column()
184             col.itemR(con, "iterations")
185             col.itemR(con, "chain_length")
186
187             col.itemL(text="Weight:")
188             col.itemR(con, "weight", text="Position", slider=True)
189             sub = col.column()
190             sub.active = con.rotation
191             sub.itemR(con, "orient_weight", text="Rotation", slider=True)
192             
193             if col2:
194                 col = split.column()
195             col.itemR(con, "tail")
196             col.itemR(con, "stretch")
197             col.itemS()
198             col.itemR(con, "targetless")
199             col.itemR(con, "rotation")
200
201     def IK_COPY_POSE(self, context, layout, con, col2):
202         self.target_template(layout, con, col2)
203         self.ik_template(layout, con, col2)
204
205         row = layout.row()
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")
210         row = split.row()
211         row.itemR(con, "weight", text="Weight", slider=True)
212         row.active = con.position
213         split = layout.split(percentage=0.33)
214         row = split.row()
215         row.itemL(text="Lock:")
216         row = split.row()
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
221
222         split = layout.split(percentage=0.33)
223         split.row().itemR(con, "rotation")
224         row = split.row()
225         row.itemR(con, "orient_weight", text="Weight", slider=True)
226         row.active = con.rotation
227         split = layout.split(percentage=0.33)
228         row = split.row()
229         row.itemL(text="Lock:")
230         row = split.row()
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
235
236     def IK_DISTANCE(self, context, layout, con, col2):
237         self.target_template(layout, con, col2)
238         self.ik_template(layout, con, col2)
239
240         layout.itemR(con, "limit_mode")
241         row = layout.row()
242         row.itemR(con, "weight", text="Weight", slider=True)
243         row.itemR(con, "distance", text="Distance", slider=True)
244
245     def FOLLOW_PATH(self, context, layout, con, col2):
246         self.target_template(layout, con, col2)
247
248         split = layout.split()
249
250         col = split.column()
251         col.itemR(con, "use_curve_follow")
252         col.itemR(con, "use_curve_radius")
253
254         if col2:
255             col = split.column()
256         col.itemR(con, "use_fixed_position")
257         if con.use_fixed_position:
258             col.itemR(con, "offset_factor", text="Offset")
259         else:
260             col.itemR(con, "offset")
261
262         row = layout.row()
263         if col2:
264             row.itemL(text="Forward:")
265         row.itemR(con, "forward", expand=True)
266
267         row = layout.row()
268         row.itemR(con, "up", text="Up")
269         if col2:
270             row.itemL()
271
272     def LIMIT_ROTATION(self, context, layout, con, col2):
273
274         split = layout.split()
275
276         col = split.column(align=True)
277         col.itemR(con, "use_limit_x")
278         sub = col.column()
279         sub.active = con.use_limit_x
280         sub.itemR(con, "minimum_x", text="Min")
281         sub.itemR(con, "maximum_x", text="Max")
282
283         if col2:
284             col = split.column(align=True)
285         col.itemR(con, "use_limit_y")
286         sub = col.column()
287         sub.active = con.use_limit_y
288         sub.itemR(con, "minimum_y", text="Min")
289         sub.itemR(con, "maximum_y", text="Max")
290
291         if col2:
292             col = split.column(align=True)
293         col.itemR(con, "use_limit_z")
294         sub = col.column()
295         sub.active = con.use_limit_z
296         sub.itemR(con, "minimum_z", text="Min")
297         sub.itemR(con, "maximum_z", text="Max")
298
299         row = layout.row()
300         row.itemR(con, "limit_transform")
301         if col2:
302             row.itemL()
303
304         row = layout.row()
305         if col2:
306             row.itemL(text="Convert:")
307         row.itemR(con, "owner_space", text="")
308
309     def LIMIT_LOCATION(self, context, layout, con, col2):
310         split = layout.split()
311
312         col = split.column()
313         col.itemR(con, "use_minimum_x")
314         sub = col.column()
315         sub.active = con.use_minimum_x
316         sub.itemR(con, "minimum_x", text="")
317         col.itemR(con, "use_maximum_x")
318         sub = col.column()
319         sub.active = con.use_maximum_x
320         sub.itemR(con, "maximum_x", text="")
321
322         if col2:
323             col = split.column()
324         col.itemR(con, "use_minimum_y")
325         sub = col.column()
326         sub.active = con.use_minimum_y
327         sub.itemR(con, "minimum_y", text="")
328         col.itemR(con, "use_maximum_y")
329         sub = col.column()
330         sub.active = con.use_maximum_y
331         sub.itemR(con, "maximum_y", text="")
332
333         if col2:
334             col = split.column()
335         col.itemR(con, "use_minimum_z")
336         sub = col.column()
337         sub.active = con.use_minimum_z
338         sub.itemR(con, "minimum_z", text="")
339         col.itemR(con, "use_maximum_z")
340         sub = col.column()
341         sub.active = con.use_maximum_z
342         sub.itemR(con, "maximum_z", text="")
343
344         row = layout.row()
345         row.itemR(con, "limit_transform")
346         if col2:
347             row.itemL()
348
349         row = layout.row()
350         if col2:
351             row.itemL(text="Convert:")
352         row.itemR(con, "owner_space", text="")
353
354     def LIMIT_SCALE(self, context, layout, con, col2):
355         split = layout.split()
356
357         col = split.column()
358         col.itemR(con, "use_minimum_x")
359         sub = col.column()
360         sub.active = con.use_minimum_x
361         sub.itemR(con, "minimum_x", text="")
362         col.itemR(con, "use_maximum_x")
363         sub = col.column()
364         sub.active = con.use_maximum_x
365         sub.itemR(con, "maximum_x", text="")
366
367         if col2:
368             col = split.column()
369         col.itemR(con, "use_minimum_y")
370         sub = col.column()
371         sub.active = con.use_minimum_y
372         sub.itemR(con, "minimum_y", text="")
373         col.itemR(con, "use_maximum_y")
374         sub = col.column()
375         sub.active = con.use_maximum_y
376         sub.itemR(con, "maximum_y", text="")
377
378         if col2:
379             col = split.column()
380         col.itemR(con, "use_minimum_z")
381         sub = col.column()
382         sub.active = con.use_minimum_z
383         sub.itemR(con, "minimum_z", text="")
384         col.itemR(con, "use_maximum_z")
385         sub = col.column()
386         sub.active = con.use_maximum_z
387         sub.itemR(con, "maximum_z", text="")
388
389         row = layout.row()
390         row.itemR(con, "limit_transform")
391         if col2:
392             row.itemL()
393
394         row = layout.row()
395         if col2:
396             row.itemL(text="Convert:")
397         row.itemR(con, "owner_space", text="")
398
399     def COPY_ROTATION(self, context, layout, con, col2):
400         self.target_template(layout, con, col2)
401
402         split = layout.split()
403
404         col = split.column()
405         col.itemR(con, "rotate_like_x", text="X")
406         sub = col.column()
407         sub.active = con.rotate_like_x
408         sub.itemR(con, "invert_x", text="Invert")
409
410         col = split.column()
411         col.itemR(con, "rotate_like_y", text="Y")
412         sub = col.column()
413         sub.active = con.rotate_like_y
414         sub.itemR(con, "invert_y", text="Invert")
415
416         col = split.column()
417         col.itemR(con, "rotate_like_z", text="Z")
418         sub = col.column()
419         sub.active = con.rotate_like_z
420         sub.itemR(con, "invert_z", text="Invert")
421
422         layout.itemR(con, "offset")
423
424         self.space_template(layout, con, col2)
425
426     def COPY_LOCATION(self, context, layout, con, col2):
427         self.target_template(layout, con, col2)
428
429         split = layout.split()
430
431         col = split.column()
432         col.itemR(con, "locate_like_x", text="X")
433         sub = col.column()
434         sub.active = con.locate_like_x
435         sub.itemR(con, "invert_x", text="Invert")
436
437         col = split.column()
438         col.itemR(con, "locate_like_y", text="Y")
439         sub = col.column()
440         sub.active = con.locate_like_y
441         sub.itemR(con, "invert_y", text="Invert")
442
443         col = split.column()
444         col.itemR(con, "locate_like_z", text="Z")
445         sub = col.column()
446         sub.active = con.locate_like_z
447         sub.itemR(con, "invert_z", text="Invert")
448
449         layout.itemR(con, "offset")
450
451         self.space_template(layout, con, col2)
452
453     def COPY_SCALE(self, context, layout, con, col2):
454         self.target_template(layout, con, col2)
455
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")
460
461         layout.itemR(con, "offset")
462
463         self.space_template(layout, con, col2)
464
465     #def SCRIPT(self, context, layout, con):
466
467     def ACTION(self, context, layout, con, col2):
468         self.target_template(layout, con, col2)
469
470         if col2:
471             layout.itemR(con, "action")
472         else:
473             layout.itemR(con, "action", text="")
474         
475         if col2:
476             layout.itemR(con, "transform_channel")
477         else:
478             layout.itemR(con, "transform_channel", text="")
479
480         split = layout.split()
481
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")
486
487         if col2:
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")
492
493         row = layout.row()
494         if col2:
495             row.itemL(text="Convert:")
496         row.itemR(con, "target_space", text="")
497
498     def LOCKED_TRACK(self, context, layout, con, col2):
499         self.target_template(layout, con, col2)
500
501         row = layout.row()
502         if col2:
503             row.itemL(text="To:")
504         row.itemR(con, "track", expand=True)
505
506         row = layout.row()
507         if col2:
508             row.itemL(text="Lock:")
509         row.itemR(con, "locked", expand=True)
510
511     def LIMIT_DISTANCE(self, context, layout, con, col2):
512         self.target_template(layout, con, col2)
513
514         col = layout.column(align=True)
515         col.itemR(con, "distance")
516         col.itemO("constraint.limitdistance_reset")
517
518         row = layout.row()
519         row.itemL(text="Clamp Region:")
520         row.itemR(con, "limit_mode", text="")
521
522     def STRETCH_TO(self, context, layout, con, col2):
523         self.target_template(layout, con, col2)
524
525         split = layout.split()
526
527         col = split.column()
528         col.itemR(con, "original_length", text="Rest Length")
529         
530         if col2:
531             col = split.column()
532         col.itemO("constraint.stretchto_reset", text="Reset")
533
534         col = layout.column()
535         col.itemR(con, "bulge", text="Volume Variation")
536
537         row = layout.row()
538         if col2:
539             row.itemL(text="Volume:")
540         row.itemR(con, "volume", expand=True)
541         if not col2:
542             row = layout.row()
543         row.itemL(text="Plane:")
544         row.itemR(con, "keep_axis", expand=True)
545
546     def FLOOR(self, context, layout, con, col2):
547         self.target_template(layout, con, col2)
548
549         split = layout.split()
550
551         col = split.column()
552         col.itemR(con, "sticky")
553         
554         if col2:
555             col = split.column()
556         col.itemR(con, "use_rotation")
557
558         layout.itemR(con, "offset")
559
560         row = layout.row()
561         if col2:
562             row.itemL(text="Min/Max:")
563         row.itemR(con, "floor_location", expand=True)
564
565     def RIGID_BODY_JOINT(self, context, layout, con, col2):
566         self.target_template(layout, con, col2)
567
568         if col2:
569             layout.itemR(con, "pivot_type")
570         else:
571             layout.itemR(con, "pivot_type", text="")
572         if col2:
573             layout.itemR(con, "child")
574         else:
575             layout.itemR(con, "child", text="")
576
577         split = layout.split()
578
579         col = split.column()
580         col.itemR(con, "disable_linked_collision", text="No Collision")
581         
582         if col2:
583             col = split.column()
584         col.itemR(con, "draw_pivot", text="Display Pivot")
585
586         split = layout.split()
587
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")
593
594         if col2:
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")
600
601         #Missing: Limit arrays (not wrapped in RNA yet)
602
603     def CLAMP_TO(self, context, layout, con, col2):
604         self.target_template(layout, con, col2)
605
606         row = layout.row()
607         if col2:
608             row.itemL(text="Main Axis:")
609         row.itemR(con, "main_axis", expand=True)
610
611         row = layout.row()
612         row.itemR(con, "cyclic")
613
614     def TRANSFORM(self, context, layout, con, col2):
615         self.target_template(layout, con, col2)
616
617         layout.itemR(con, "extrapolate_motion", text="Extrapolate")
618         
619         col = layout.column()
620         col.row().itemL(text="Source:")
621         col.row().itemR(con, "map_from", expand=True)
622         
623         split = layout.split()
624         
625         sub = split.column(align=True)
626         sub.itemL(text="X:")
627         sub.itemR(con, "from_min_x", text="Min")
628         sub.itemR(con, "from_max_x", text="Max")
629
630         if col2:
631             sub = split.column(align=True)
632         sub.itemL(text="Y:")
633         sub.itemR(con, "from_min_y", text="Min")
634         sub.itemR(con, "from_max_y", text="Max")
635
636         if col2:
637             sub = split.column(align=True)
638         sub.itemL(text="Z:")
639         sub.itemR(con, "from_min_z", text="Min")
640         sub.itemR(con, "from_max_z", text="Max")
641
642         split = layout.split()
643
644         col = split.column()
645         col.itemL(text="Destination:")
646         col.row().itemR(con, "map_to", expand=True)
647
648         split = layout.split()
649         
650         col = split.column()
651         col.itemL(text="X:")
652         col.row().itemR(con, "map_to_x_from", expand=True)
653         
654         sub = col.column(align=True)
655         sub.itemR(con, "to_min_x", text="Min")
656         sub.itemR(con, "to_max_x", text="Max")
657         
658         if col2:
659             col = split.column()
660         col.itemL(text="Y:")
661         col.row().itemR(con, "map_to_y_from", expand=True)
662         
663         sub = col.column(align=True)
664         sub.itemR(con, "to_min_y", text="Min")
665         sub.itemR(con, "to_max_y", text="Max")
666         
667         if col2:
668             col = split.column()
669         col.itemL(text="Z:")
670         col.row().itemR(con, "map_to_z_from", expand=True)
671         
672         sub = col.column(align=True)
673         sub.itemR(con, "to_min_z", text="Min")
674         sub.itemR(con, "to_max_z", text="Max")
675
676         self.space_template(layout, con, col2)
677
678     def SHRINKWRAP(self, context, layout, con, col2):
679         self.target_template(layout, con, col2)
680
681         layout.itemR(con, "distance")
682         layout.itemR(con, "shrinkwrap_type")
683
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")
689
690     def DAMPED_TRACK(self, context, layout, con, col2):
691         self.target_template(layout, con, col2)
692
693         row = layout.row()
694         if col2:
695             row.itemL(text="To:")
696         row.itemR(con, "track", expand=True)
697
698     def SPLINE_IK(self, context, layout, con, col2):
699         self.target_template(layout, con, col2)
700
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")
706
707         col = layout.column()
708         col.itemL(text="Chain Scaling:")
709         col.itemR(con, "y_scaling")
710         if col2:
711             col.itemR(con, "xz_scaling_mode")
712         else:
713             col.itemR(con, "xz_scaling_mode", text="")
714
715
716 class OBJECT_PT_constraints(ConstraintButtonsPanel):
717     bl_label = "Object Constraints"
718     bl_context = "constraint"
719
720     def poll(self, context):
721         return (context.object)
722
723     def draw(self, context):
724         layout = self.layout
725         ob = context.object
726         col2 = context.region.width > narrowui
727
728         row = layout.row()
729         row.item_menu_enumO("object.constraint_add", "type")
730         if col2:
731             row.itemL()
732
733         for con in ob.constraints:
734             self.draw_constraint(context, con)
735
736
737 class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
738     bl_label = "Inverse Kinematics"
739     bl_default_closed = True
740     bl_context = "bone_constraint"
741
742     def poll(self, context):
743         ob = context.object
744         bone = context.bone
745
746         if ob and bone:
747             pchan = ob.pose.bones[bone.name]
748             return pchan.has_ik
749
750         return False
751
752     def draw(self, context):
753         layout = self.layout
754
755         ob = context.object
756         bone = context.bone
757         pchan = ob.pose.bones[bone.name]
758         col2 = context.region.width > narrowui
759
760         row = layout.row()
761         row.itemR(ob.pose, "ik_solver")
762
763         split = layout.split(percentage=0.25)
764         split.itemR(pchan, "ik_dof_x", text="X")
765         row = split.row()
766         row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
767         row.active = pchan.ik_dof_x
768
769         if col2:
770             split = layout.split(percentage=0.25)
771             sub = split.row()
772         else:
773             sub = layout.column(align=True)
774         sub.itemR(pchan, "ik_limit_x", text="Limit")
775         sub.active = pchan.ik_dof_x
776         if col2:
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
781
782         split = layout.split(percentage=0.25)
783         split.itemR(pchan, "ik_dof_y", text="Y")
784         row = split.row()
785         row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
786         row.active = pchan.ik_dof_y
787
788         if col2:
789             split = layout.split(percentage=0.25)
790             sub = split.row()
791         else:
792             sub = layout.column(align=True)
793         sub.itemR(pchan, "ik_limit_y", text="Limit")
794         sub.active = pchan.ik_dof_y
795         if col2:
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
800
801         split = layout.split(percentage=0.25)
802         split.itemR(pchan, "ik_dof_z", text="Z")
803         sub = split.row()
804         sub.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
805         sub.active = pchan.ik_dof_z
806
807         if col2:
808             split = layout.split(percentage=0.25)
809             sub = split.row()
810         else:
811             sub = layout.column(align=True)
812         sub.itemR(pchan, "ik_limit_z", text="Limit")
813         sub.active = pchan.ik_dof_z
814         if col2:
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)
821         if col2:
822             split.itemL()
823
824         if ob.pose.ik_solver == 'ITASC':
825             split = layout.split()
826             col = split.column()
827             col.itemR(pchan, "ik_rot_control", text="Control Rotation")
828             if col2:
829                 col = split.column()
830             col.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
831             # not supported yet
832             #row = layout.row()
833             #row.itemR(pchan, "ik_lin_control", text="Joint Size")
834             #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
835
836
837 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
838     bl_label = "iTaSC parameters"
839     bl_default_closed = True
840     bl_context = "bone_constraint"
841
842     def poll(self, context):
843         ob = context.object
844         bone = context.bone
845
846         if ob and bone:
847             pchan = ob.pose.bones[bone.name]
848             return pchan.has_ik and ob.pose.ik_solver == 'ITASC' and ob.pose.ik_param
849
850         return False
851
852     def draw(self, context):
853         layout = self.layout
854
855         ob = context.object
856         itasc = ob.pose.ik_param
857         col2 = context.region.width > narrowui
858
859         layout.itemR(itasc, "mode", expand=True)
860         simulation = itasc.mode == 'SIMULATION'
861         if simulation:
862             layout.itemL(text="Reiteration:")
863             layout.itemR(itasc, "reiteration", expand=True)
864
865         split = layout.split()
866         split.active = not simulation or itasc.reiteration != 'NEVER'
867         col = split.column()
868         col.itemR(itasc, "precision")
869         
870         if col2:
871             col = split.column()
872         col.itemR(itasc, "num_iter")
873         
874
875         if simulation:
876             layout.itemR(itasc, "auto_step")
877             row = layout.row()
878             if itasc.auto_step:
879                 row.itemR(itasc, "min_step", text="Min")
880                 row.itemR(itasc, "max_step", text="Max")
881             else:
882                 row.itemR(itasc, "num_step")
883
884         layout.itemR(itasc, "solver")
885         if simulation:
886             layout.itemR(itasc, "feedback")
887             layout.itemR(itasc, "max_velocity")
888         if itasc.solver == 'DLS':
889             row = layout.row()
890             row.itemR(itasc, "dampmax", text="Damp", slider=True)
891             row.itemR(itasc, "dampeps", text="Eps", slider=True)
892
893
894 class BONE_PT_constraints(ConstraintButtonsPanel):
895     bl_label = "Bone Constraints"
896     bl_context = "bone_constraint"
897
898     def poll(self, context):
899         ob = context.object
900         return (ob and ob.type == 'ARMATURE' and context.bone)
901
902     def draw(self, context):
903         layout = self.layout
904
905         ob = context.object
906         pchan = ob.pose.bones[context.bone.name]
907         col2 = context.region.width > narrowui
908
909         row = layout.row()
910         row.item_menu_enumO("pose.constraint_add", "type")
911         if col2:
912             row.itemL()
913
914         for con in pchan.constraints:
915             self.draw_constraint(context, con)
916
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)