272fc6b8c6c9c4cd3f1731491ddf92cc1927d6c5
[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         wide_ui = 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, wide_ui)
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, wide_ui, target=True, owner=True):
45         if target or owner:
46
47             split = layout.split(percentage=0.2)
48
49             if wide_ui:
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 wide_ui:
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, wide_ui, subtargets=True):
68         if wide_ui:
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 wide_ui:
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, wide_ui):
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, wide_ui):
109         self.target_template(layout, con, wide_ui)
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 wide_ui:
137             col = split.column()
138         col.itemO("constraint.childof_clear_inverse")
139
140     def TRACK_TO(self, context, layout, con, wide_ui):
141         self.target_template(layout, con, wide_ui)
142
143         row = layout.row()
144         if wide_ui:
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 wide_ui:
154             col = split.column()
155         col.itemR(con, "target_z")
156
157         self.space_template(layout, con, wide_ui)
158
159     def IK(self, context, layout, con, wide_ui):
160         if context.object.pose.ik_solver == "ITASC":
161             layout.itemR(con, "ik_type")
162             getattr(self, 'IK_' + con.ik_type)(context, layout, con, wide_ui)
163         else:
164             # Legacy IK constraint
165             self.target_template(layout, con, wide_ui)
166             if wide_ui:
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 wide_ui:
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 wide_ui:
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 wide_ui:
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, wide_ui):
202         self.target_template(layout, con, wide_ui)
203         self.ik_template(layout, con, wide_ui)
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, wide_ui):
237         self.target_template(layout, con, wide_ui)
238         self.ik_template(layout, con, wide_ui)
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, wide_ui):
246         self.target_template(layout, con, wide_ui)
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 wide_ui:
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 wide_ui:
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 wide_ui:
270             row.itemL()
271
272     def LIMIT_ROTATION(self, context, layout, con, wide_ui):
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 wide_ui:
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 wide_ui:
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 wide_ui:
302             row.itemL()
303
304         row = layout.row()
305         if wide_ui:
306             row.itemL(text="Convert:")
307         row.itemR(con, "owner_space", text="")
308
309     def LIMIT_LOCATION(self, context, layout, con, wide_ui):
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 wide_ui:
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 wide_ui:
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 wide_ui:
347             row.itemL()
348
349         row = layout.row()
350         if wide_ui:
351             row.itemL(text="Convert:")
352         row.itemR(con, "owner_space", text="")
353
354     def LIMIT_SCALE(self, context, layout, con, wide_ui):
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 wide_ui:
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 wide_ui:
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 wide_ui:
392             row.itemL()
393
394         row = layout.row()
395         if wide_ui:
396             row.itemL(text="Convert:")
397         row.itemR(con, "owner_space", text="")
398
399     def COPY_ROTATION(self, context, layout, con, wide_ui):
400         self.target_template(layout, con, wide_ui)
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, wide_ui)
425
426     def COPY_LOCATION(self, context, layout, con, wide_ui):
427         self.target_template(layout, con, wide_ui)
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, wide_ui)
452
453     def COPY_SCALE(self, context, layout, con, wide_ui):
454         self.target_template(layout, con, wide_ui)
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, wide_ui)
464
465     #def SCRIPT(self, context, layout, con):
466
467     def ACTION(self, context, layout, con, wide_ui):
468         self.target_template(layout, con, wide_ui)
469
470         if wide_ui:
471             layout.itemR(con, "action")
472         else:
473             layout.itemR(con, "action", text="")
474
475         if wide_ui:
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 wide_ui:
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 wide_ui:
495             row.itemL(text="Convert:")
496         row.itemR(con, "target_space", text="")
497
498     def LOCKED_TRACK(self, context, layout, con, wide_ui):
499         self.target_template(layout, con, wide_ui)
500
501         row = layout.row()
502         if wide_ui:
503             row.itemL(text="To:")
504         row.itemR(con, "track", expand=True)
505
506         row = layout.row()
507         if wide_ui:
508             row.itemL(text="Lock:")
509         row.itemR(con, "locked", expand=True)
510
511     def LIMIT_DISTANCE(self, context, layout, con, wide_ui):
512         self.target_template(layout, con, wide_ui)
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, wide_ui):
523         self.target_template(layout, con, wide_ui)
524
525         split = layout.split()
526
527         col = split.column()
528         col.itemR(con, "original_length", text="Rest Length")
529
530         if wide_ui:
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 wide_ui:
539             row.itemL(text="Volume:")
540         row.itemR(con, "volume", expand=True)
541         if not wide_ui:
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, wide_ui):
547         self.target_template(layout, con, wide_ui)
548
549         split = layout.split()
550
551         col = split.column()
552         col.itemR(con, "sticky")
553
554         if wide_ui:
555             col = split.column()
556         col.itemR(con, "use_rotation")
557
558         layout.itemR(con, "offset")
559
560         row = layout.row()
561         if wide_ui:
562             row.itemL(text="Min/Max:")
563         row.itemR(con, "floor_location", expand=True)
564
565     def RIGID_BODY_JOINT(self, context, layout, con, wide_ui):
566         self.target_template(layout, con, wide_ui)
567
568         if wide_ui:
569             layout.itemR(con, "pivot_type")
570         else:
571             layout.itemR(con, "pivot_type", text="")
572         if wide_ui:
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 wide_ui:
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 wide_ui:
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, wide_ui):
604         self.target_template(layout, con, wide_ui)
605
606         row = layout.row()
607         if wide_ui:
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, wide_ui):
615         self.target_template(layout, con, wide_ui)
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 wide_ui:
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 wide_ui:
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 wide_ui:
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 wide_ui:
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, wide_ui)
677
678     def SHRINKWRAP(self, context, layout, con, wide_ui):
679         self.target_template(layout, con, wide_ui)
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, wide_ui):
691         self.target_template(layout, con, wide_ui)
692
693         row = layout.row()
694         if wide_ui:
695             row.itemL(text="To:")
696         row.itemR(con, "track", expand=True)
697
698     def SPLINE_IK(self, context, layout, con, wide_ui):
699         self.target_template(layout, con, wide_ui)
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_stretch")
710         if wide_ui:
711             col.itemR(con, "xz_scaling_mode")
712         else:
713             col.itemR(con, "xz_scaling_mode", text="")
714         col.itemR(con, "use_curve_radius")
715
716
717 class OBJECT_PT_constraints(ConstraintButtonsPanel):
718     bl_label = "Object Constraints"
719     bl_context = "constraint"
720
721     def poll(self, context):
722         return (context.object)
723
724     def draw(self, context):
725         layout = self.layout
726         ob = context.object
727         wide_ui = context.region.width > narrowui
728
729         row = layout.row()
730         row.item_menu_enumO("object.constraint_add", "type")
731         if wide_ui:
732             row.itemL()
733
734         for con in ob.constraints:
735             self.draw_constraint(context, con)
736
737
738 class BONE_PT_inverse_kinematics(ConstraintButtonsPanel):
739     bl_label = "Inverse Kinematics"
740     bl_default_closed = True
741     bl_context = "bone_constraint"
742
743     def poll(self, context):
744         ob = context.object
745         bone = context.bone
746
747         if ob and bone:
748             pchan = ob.pose.bones[bone.name]
749             return pchan.has_ik
750
751         return False
752
753     def draw(self, context):
754         layout = self.layout
755
756         ob = context.object
757         bone = context.bone
758         pchan = ob.pose.bones[bone.name]
759         wide_ui = context.region.width > narrowui
760
761         row = layout.row()
762         row.itemR(ob.pose, "ik_solver")
763
764         split = layout.split(percentage=0.25)
765         split.itemR(pchan, "ik_dof_x", text="X")
766         row = split.row()
767         row.itemR(pchan, "ik_stiffness_x", text="Stiffness", slider=True)
768         row.active = pchan.ik_dof_x
769
770         if wide_ui:
771             split = layout.split(percentage=0.25)
772             sub = split.row()
773         else:
774             sub = layout.column(align=True)
775         sub.itemR(pchan, "ik_limit_x", text="Limit")
776         sub.active = pchan.ik_dof_x
777         if wide_ui:
778             sub = split.row(align=True)
779         sub.itemR(pchan, "ik_min_x", text="")
780         sub.itemR(pchan, "ik_max_x", text="")
781         sub.active = pchan.ik_dof_x and pchan.ik_limit_x
782
783         split = layout.split(percentage=0.25)
784         split.itemR(pchan, "ik_dof_y", text="Y")
785         row = split.row()
786         row.itemR(pchan, "ik_stiffness_y", text="Stiffness", slider=True)
787         row.active = pchan.ik_dof_y
788
789         if wide_ui:
790             split = layout.split(percentage=0.25)
791             sub = split.row()
792         else:
793             sub = layout.column(align=True)
794         sub.itemR(pchan, "ik_limit_y", text="Limit")
795         sub.active = pchan.ik_dof_y
796         if wide_ui:
797             sub = split.row(align=True)
798         sub.itemR(pchan, "ik_min_y", text="")
799         sub.itemR(pchan, "ik_max_y", text="")
800         sub.active = pchan.ik_dof_y and pchan.ik_limit_y
801
802         split = layout.split(percentage=0.25)
803         split.itemR(pchan, "ik_dof_z", text="Z")
804         sub = split.row()
805         sub.itemR(pchan, "ik_stiffness_z", text="Stiffness", slider=True)
806         sub.active = pchan.ik_dof_z
807
808         if wide_ui:
809             split = layout.split(percentage=0.25)
810             sub = split.row()
811         else:
812             sub = layout.column(align=True)
813         sub.itemR(pchan, "ik_limit_z", text="Limit")
814         sub.active = pchan.ik_dof_z
815         if wide_ui:
816             sub = split.row(align=True)
817         sub.itemR(pchan, "ik_min_z", text="")
818         sub.itemR(pchan, "ik_max_z", text="")
819         sub.active = pchan.ik_dof_z and pchan.ik_limit_z
820         split = layout.split()
821         split.itemR(pchan, "ik_stretch", text="Stretch", slider=True)
822         if wide_ui:
823             split.itemL()
824
825         if ob.pose.ik_solver == 'ITASC':
826             split = layout.split()
827             col = split.column()
828             col.itemR(pchan, "ik_rot_control", text="Control Rotation")
829             if wide_ui:
830                 col = split.column()
831             col.itemR(pchan, "ik_rot_weight", text="Weight", slider=True)
832             # not supported yet
833             #row = layout.row()
834             #row.itemR(pchan, "ik_lin_control", text="Joint Size")
835             #row.itemR(pchan, "ik_lin_weight", text="Weight", slider=True)
836
837
838 class BONE_PT_iksolver_itasc(ConstraintButtonsPanel):
839     bl_label = "iTaSC parameters"
840     bl_default_closed = True
841     bl_context = "bone_constraint"
842
843     def poll(self, context):
844         ob = context.object
845         bone = context.bone
846
847         if ob and bone:
848             pchan = ob.pose.bones[bone.name]
849             return pchan.has_ik and ob.pose.ik_solver == 'ITASC' and ob.pose.ik_param
850
851         return False
852
853     def draw(self, context):
854         layout = self.layout
855
856         ob = context.object
857         itasc = ob.pose.ik_param
858         wide_ui = context.region.width > narrowui
859
860         layout.itemR(itasc, "mode", expand=True)
861         simulation = itasc.mode == 'SIMULATION'
862         if simulation:
863             layout.itemL(text="Reiteration:")
864             layout.itemR(itasc, "reiteration", expand=True)
865
866         split = layout.split()
867         split.active = not simulation or itasc.reiteration != 'NEVER'
868         col = split.column()
869         col.itemR(itasc, "precision")
870
871         if wide_ui:
872             col = split.column()
873         col.itemR(itasc, "num_iter")
874
875
876         if simulation:
877             layout.itemR(itasc, "auto_step")
878             row = layout.row()
879             if itasc.auto_step:
880                 row.itemR(itasc, "min_step", text="Min")
881                 row.itemR(itasc, "max_step", text="Max")
882             else:
883                 row.itemR(itasc, "num_step")
884
885         layout.itemR(itasc, "solver")
886         if simulation:
887             layout.itemR(itasc, "feedback")
888             layout.itemR(itasc, "max_velocity")
889         if itasc.solver == 'DLS':
890             row = layout.row()
891             row.itemR(itasc, "dampmax", text="Damp", slider=True)
892             row.itemR(itasc, "dampeps", text="Eps", slider=True)
893
894
895 class BONE_PT_constraints(ConstraintButtonsPanel):
896     bl_label = "Bone Constraints"
897     bl_context = "bone_constraint"
898
899     def poll(self, context):
900         ob = context.object
901         return (ob and ob.type == 'ARMATURE' and context.bone)
902
903     def draw(self, context):
904         layout = self.layout
905
906         ob = context.object
907         pchan = ob.pose.bones[context.bone.name]
908         wide_ui = context.region.width > narrowui
909
910         row = layout.row()
911         row.item_menu_enumO("pose.constraint_add", "type")
912         if wide_ui:
913             row.itemL()
914
915         for con in pchan.constraints:
916             self.draw_constraint(context, con)
917
918 bpy.types.register(OBJECT_PT_constraints)
919 bpy.types.register(BONE_PT_iksolver_itasc)
920 bpy.types.register(BONE_PT_inverse_kinematics)
921 bpy.types.register(BONE_PT_constraints)