Bone constraints are now in a separate tab. It's more consistent
[blender.git] / release / ui / buttons_object_constraint.py
1
2 import bpy
3
4 class ConstraintButtonsPanel(bpy.types.Panel):
5         __space_type__ = 'PROPERTIES'
6         __region_type__ = 'WINDOW'
7         __context__ = "constraint"
8
9         def draw_constraint(self, con):
10                 layout = self.layout
11                 
12                 box = layout.template_constraint(con)
13
14                 if box:
15                         # match enum type to our functions, avoids a lookup table.
16                         getattr(self, con.type)(box, con)
17         
18                         # show/key buttons here are most likely obsolete now, with
19                         # keyframing functionality being part of every button
20                         if con.type not in ('RIGID_BODY_JOINT', 'NULL'):
21                                 box.itemR(con, "influence")
22         
23         def space_template(self, layout, con, target=True, owner=True):
24                 if target or owner:
25                         row = layout.row()
26
27                         row.itemL(text="Convert:")
28
29                         if target:
30                                 row.itemR(con, "target_space", text="")
31
32                         if target and owner:
33                                 row.itemL(icon='ICON_ARROW_LEFTRIGHT')
34
35                         if owner:
36                                 row.itemR(con, "owner_space", text="")
37                         
38         def target_template(self, layout, con, subtargets=True):
39                 layout.itemR(con, "target") # XXX limiting settings for only 'curves' or some type of object
40                 
41                 if con.target and subtargets:
42                         if con.target.type == 'ARMATURE':
43                                 layout.item_pointerR(con, "subtarget", con.target.data, "bones", text="Bone")
44                                 
45                                 if con.type == 'COPY_LOCATION':
46                                         row = layout.row()
47                                         row.itemL(text="Head/Tail:")
48                                         row.itemR(con, "head_tail", text="")
49                         elif con.target.type in ('MESH', 'LATTICE'):
50                                 layout.item_pointerR(con, "subtarget", con.target, "vertex_groups", text="Vertex Group")
51         
52         def CHILD_OF(self, layout, con):
53                 self.target_template(layout, con)
54
55                 split = layout.split()
56                 
57                 col = split.column()
58                 col.itemL(text="Location:")
59                 col.itemR(con, "locationx", text="X")
60                 col.itemR(con, "locationy", text="Y")
61                 col.itemR(con, "locationz", text="Z")
62                 
63                 col = split.column()
64                 col.itemL(text="Rotation:")
65                 col.itemR(con, "rotationx", text="X")
66                 col.itemR(con, "rotationy", text="Y")
67                 col.itemR(con, "rotationz", text="Z")
68                 
69                 col = split.column()
70                 col.itemL(text="Scale:")
71                 col.itemR(con, "sizex", text="X")
72                 col.itemR(con, "sizey", text="Y")
73                 col.itemR(con, "sizez", text="Z")
74                 
75                 row = layout.row()
76                 row.itemO("constraint.childof_set_inverse")
77                 row.itemO("constraint.childof_clear_inverse")
78                 
79         def TRACK_TO(self, layout, con):
80                 self.target_template(layout, con)
81                 
82                 row = layout.row()
83                 row.itemL(text="To:")
84                 row.itemR(con, "track", expand=True)
85                 
86                 row = layout.row()
87                 #row.itemR(con, "up", text="Up", expand=True) # XXX: up and expand don't play nice together
88                 row.itemR(con, "up", text="Up")
89                 row.itemR(con, "target_z")
90                 
91                 self.space_template(layout, con)
92                 
93         def IK(self, layout, con):
94                 self.target_template(layout, con)
95                 
96                 layout.itemR(con, "pole_target")
97         
98                 if con.pole_target and con.pole_target.type == 'ARMATURE':
99                         layout.item_pointerR(con, "pole_subtarget", con.pole_target.data, "bones", text="Bone")
100                 
101                 split = layout.split()
102         
103                 col = split.column()
104                 col.itemR(con, "iterations")
105                 col.itemR(con, "chain_length")
106                 sub = col.column()
107                 sub.active = con.pole_target
108                 sub.itemR(con, "pole_angle")
109                 col.itemL(text="Weight:")
110                 col.itemR(con, "weight", text="Position", slider=True)
111                 sub = col.column()
112                 sub.active = con.rotation
113                 sub.itemR(con, "orient_weight", text="Rotation", slider=True)
114                 
115                 col = split.column()
116                 col.itemR(con, "tail")
117                 col.itemR(con, "rotation")
118                 col.itemR(con, "targetless")
119                 col.itemR(con, "stretch")
120                 
121         def FOLLOW_PATH(self, layout, con):
122                 self.target_template(layout, con)
123                 
124                 split = layout.split()
125                 
126                 col = split.column()
127                 col.itemR(con, "use_curve_follow")
128                 col.itemR(con, "use_curve_radius")
129                 
130                 col = split.column()
131                 col.itemR(con, "use_fixed_position")
132                 if con.use_fixed_position:
133                         col.itemR(con, "offset_percentage", text="Offset")
134                 else:
135                         col.itemR(con, "offset")
136                 
137                 row = layout.row()
138                 row.itemL(text="Forward:")
139                 row.itemR(con, "forward", expand=True)
140                 
141                 row = layout.row()
142                 row.itemR(con, "up", text="Up")
143                 row.itemL()
144                 
145         def LIMIT_ROTATION(self, layout, con):
146                 
147                 split = layout.split()
148                 
149                 col = split.column()
150                 col.itemR(con, "use_limit_x")
151                 sub = col.column()
152                 sub.active = con.use_limit_x
153                 sub.itemR(con, "minimum_x", text="Min")
154                 sub.itemR(con, "maximum_x", text="Max")
155                 
156                 col = split.column()
157                 col.itemR(con, "use_limit_y")
158                 sub = col.column()
159                 sub.active = con.use_limit_y
160                 sub.itemR(con, "minimum_y", text="Min")
161                 sub.itemR(con, "maximum_y", text="Max")
162                 
163                 col = split.column()
164                 col.itemR(con, "use_limit_z")
165                 sub = col.column()
166                 sub.active = con.use_limit_z
167                 sub.itemR(con, "minimum_z", text="Min")
168                 sub.itemR(con, "maximum_z", text="Max")
169                 
170                 row = layout.row()
171                 row.itemR(con, "limit_transform")
172                 row.itemL()
173                 
174                 row = layout.row()
175                 row.itemL(text="Convert:")
176                 row.itemR(con, "owner_space", text="")
177                 
178         def LIMIT_LOCATION(self, layout, con):
179                 split = layout.split()
180                 
181                 col = split.column()
182                 col.itemR(con, "use_minimum_x")
183                 sub = col.column()
184                 sub.active = con.use_minimum_x
185                 sub.itemR(con, "minimum_x", text="")
186                 col.itemR(con, "use_maximum_x")
187                 sub = col.column()
188                 sub.active = con.use_maximum_x
189                 sub.itemR(con, "maximum_x", text="")
190                 
191                 col = split.column()
192                 col.itemR(con, "use_minimum_y")
193                 sub = col.column()
194                 sub.active = con.use_minimum_y
195                 sub.itemR(con, "minimum_y", text="")
196                 col.itemR(con, "use_maximum_y")
197                 sub = col.column()
198                 sub.active = con.use_maximum_y
199                 sub.itemR(con, "maximum_y", text="")
200                 
201                 col = split.column()
202                 col.itemR(con, "use_minimum_z")
203                 sub = col.column()
204                 sub.active = con.use_minimum_z
205                 sub.itemR(con, "minimum_z", text="")
206                 col.itemR(con, "use_maximum_z")
207                 sub = col.column()
208                 sub.active = con.use_maximum_z
209                 sub.itemR(con, "maximum_z", text="")
210         
211                 row = layout.row()
212                 row.itemR(con, "limit_transform")
213                 row.itemL()
214                 
215                 row = layout.row()
216                 row.itemL(text="Convert:")
217                 row.itemR(con, "owner_space", text="")
218                 
219         def LIMIT_SCALE(self, layout, con):
220                 split = layout.split()
221
222                 col = split.column()
223                 col.itemR(con, "use_minimum_x")
224                 sub = col.column()
225                 sub.active = con.use_minimum_x
226                 sub.itemR(con, "minimum_x", text="")
227                 col.itemR(con, "use_maximum_x")
228                 sub = col.column()
229                 sub.active = con.use_maximum_x
230                 sub.itemR(con, "maximum_x", text="")
231                 
232                 col = split.column()
233                 col.itemR(con, "use_minimum_y")
234                 sub = col.column()
235                 sub.active = con.use_minimum_y
236                 sub.itemR(con, "minimum_y", text="")
237                 col.itemR(con, "use_maximum_y")
238                 sub = col.column()
239                 sub.active = con.use_maximum_y
240                 sub.itemR(con, "maximum_y", text="")
241                 
242                 col = split.column()
243                 col.itemR(con, "use_minimum_z")
244                 sub = col.column()
245                 sub.active = con.use_minimum_z
246                 sub.itemR(con, "minimum_z", text="")
247                 col.itemR(con, "use_maximum_z")
248                 sub = col.column()
249                 sub.active = con.use_maximum_z
250                 sub.itemR(con, "maximum_z", text="")
251                 
252                 row = layout.row()
253                 row.itemR(con, "limit_transform")
254                 row.itemL()
255                 
256                 row = layout.row()
257                 row.itemL(text="Convert:")
258                 row.itemR(con, "owner_space", text="")
259         
260         def COPY_ROTATION(self, layout, con):
261                 self.target_template(layout, con)
262                 
263                 split = layout.split()
264                 
265                 col = split.column()
266                 col.itemR(con, "rotate_like_x", text="X")
267                 sub = col.column()
268                 sub.active = con.rotate_like_x
269                 sub.itemR(con, "invert_x", text="Invert")
270                 
271                 col = split.column()
272                 col.itemR(con, "rotate_like_y", text="Y")
273                 sub = col.column()
274                 sub.active = con.rotate_like_y
275                 sub.itemR(con, "invert_y", text="Invert")
276                 
277                 col = split.column()
278                 col.itemR(con, "rotate_like_z", text="Z")
279                 sub = col.column()
280                 sub.active = con.rotate_like_z
281                 sub.itemR(con, "invert_z", text="Invert")
282
283                 layout.itemR(con, "offset")
284                 
285                 self.space_template(layout, con)
286                 
287         def COPY_LOCATION(self, layout, con):
288                 self.target_template(layout, con)
289                 
290                 split = layout.split()
291                 
292                 col = split.column()
293                 col.itemR(con, "locate_like_x", text="X")
294                 sub = col.column()
295                 sub.active = con.locate_like_x
296                 sub.itemR(con, "invert_x", text="Invert")
297                 
298                 col = split.column()
299                 col.itemR(con, "locate_like_y", text="Y")
300                 sub = col.column()
301                 sub.active = con.locate_like_y
302                 sub.itemR(con, "invert_y", text="Invert")
303                 
304                 col = split.column()
305                 col.itemR(con, "locate_like_z", text="Z")
306                 sub = col.column()
307                 sub.active = con.locate_like_z
308                 sub.itemR(con, "invert_z", text="Invert")
309
310                 layout.itemR(con, "offset")
311                         
312                 self.space_template(layout, con)
313                 
314         def COPY_SCALE(self, layout, con):
315                 self.target_template(layout, con)
316                 
317                 row = layout.row(align=True)
318                 row.itemR(con, "size_like_x", text="X")
319                 row.itemR(con, "size_like_y", text="Y")
320                 row.itemR(con, "size_like_z", text="Z")
321
322                 layout.itemR(con, "offset")
323                 
324                 self.space_template(layout, con)
325                 
326         #def SCRIPT(self, layout, con):
327         
328         def ACTION(self, layout, con):
329                 self.target_template(layout, con)
330                 
331                 layout.itemR(con, "action")
332                 layout.itemR(con, "transform_channel")
333
334                 split = layout.split()
335         
336                 col = split.column(align=True)
337                 col.itemR(con, "start_frame", text="Start")
338                 col.itemR(con, "end_frame", text="End")
339                 
340                 col = split.column(align=True)
341                 col.itemR(con, "minimum", text="Min")
342                 col.itemR(con, "maximum", text="Max")
343                 
344                 row = layout.row()
345                 row.itemL(text="Convert:")
346                 row.itemR(con, "owner_space", text="")
347         
348         def LOCKED_TRACK(self, layout, con):
349                 self.target_template(layout, con)
350                 
351                 row = layout.row()
352                 row.itemL(text="To:")
353                 row.itemR(con, "track", expand=True)
354                 
355                 row = layout.row()
356                 row.itemL(text="Lock:")
357                 row.itemR(con, "locked", expand=True)
358                 
359         def LIMIT_DISTANCE(self, layout, con):
360                 self.target_template(layout, con)
361                 
362                 col = layout.column(align=True);
363                 col.itemR(con, "distance")
364                 col.itemO("constraint.limitdistance_reset")
365                 
366                 row = layout.row()
367                 row.itemL(text="Clamp Region:")
368                 row.itemR(con, "limit_mode", text="")
369                 
370         def STRETCH_TO(self, layout, con):
371                 self.target_template(layout, con)
372                 
373                 row = layout.row()
374                 row.itemR(con, "original_length", text="Rest Length")
375                 row.itemO("constraint.stretchto_reset", text="Reset")
376                 
377                 col = layout.column()
378                 col.itemR(con, "bulge", text="Volume Variation")
379                 
380                 row = layout.row()
381                 row.itemL(text="Volume:")
382                 row.itemR(con, "volume", expand=True)
383                 row.itemL(text="Plane:")
384                 row.itemR(con, "keep_axis", expand=True)
385                 
386         def FLOOR(self, layout, con):
387                 self.target_template(layout, con)
388                 
389                 row = layout.row()
390                 row.itemR(con, "sticky")
391                 row.itemR(con, "use_rotation")
392                 
393                 layout.itemR(con, "offset")
394                 
395                 row = layout.row()
396                 row.itemL(text="Min/Max:")
397                 row.itemR(con, "floor_location", expand=True)
398                 
399         def RIGID_BODY_JOINT(self, layout, con):
400                 self.target_template(layout, con)
401                 
402                 layout.itemR(con, "pivot_type")
403                 layout.itemR(con, "child")
404                 
405                 row = layout.row()
406                 row.itemR(con, "disable_linked_collision", text="No Collision")
407                 row.itemR(con, "draw_pivot", text="Display Pivot")
408                 
409                 split = layout.split()
410                 
411                 col = split.column(align=True)
412                 col.itemL(text="Pivot:")
413                 col.itemR(con, "pivot_x", text="X")
414                 col.itemR(con, "pivot_y", text="Y")
415                 col.itemR(con, "pivot_z", text="Z")
416                 
417                 col = split.column(align=True)
418                 col.itemL(text="Axis:")
419                 col.itemR(con, "axis_x", text="X")
420                 col.itemR(con, "axis_y", text="Y")
421                 col.itemR(con, "axis_z", text="Z")
422                 
423                 #Missing: Limit arrays (not wrapped in RNA yet) 
424         
425         def CLAMP_TO(self, layout, con):
426                 self.target_template(layout, con)
427                 
428                 row = layout.row()
429                 row.itemL(text="Main Axis:")
430                 row.itemR(con, "main_axis", expand=True)
431                 
432                 row = layout.row()
433                 row.itemR(con, "cyclic")
434                 
435         def TRANSFORM(self, layout, con):
436                 self.target_template(layout, con)
437                 
438                 layout.itemR(con, "extrapolate_motion", text="Extrapolate")
439                 
440                 split = layout.split()
441                 
442                 col = split.column()
443                 col.itemL(text="Source:")
444                 col.row().itemR(con, "map_from", expand=True)
445                 
446                 sub = col.row(align=True)
447                 sub.itemL(text="X:")
448                 sub.itemR(con, "from_min_x", text="")
449                 sub.itemR(con, "from_max_x", text="")
450                 
451                 sub = col.row(align=True)
452                 sub.itemL(text="Y:")
453                 sub.itemR(con, "from_min_y", text="")
454                 sub.itemR(con, "from_max_y", text="")
455                 
456                 sub = col.row(align=True)
457                 sub.itemL(text="Z:")
458                 sub.itemR(con, "from_min_z", text="")
459                 sub.itemR(con, "from_max_z", text="")
460                 
461                 split = layout.split()
462                 
463                 col = split.column()
464                 col.itemL(text="Destination:")
465                 col.row().itemR(con, "map_to", expand=True)
466
467                 sub = col.row(align=True)
468                 sub.itemR(con, "map_to_x_from", text="")
469                 sub.itemR(con, "to_min_x", text="")
470                 sub.itemR(con, "to_max_x", text="")
471                 
472                 sub = col.row(align=True)
473                 sub.itemR(con, "map_to_y_from", text="")
474                 sub.itemR(con, "to_min_y", text="")
475                 sub.itemR(con, "to_max_y", text="")
476                 
477                 sub = col.row(align=True)
478                 sub.itemR(con, "map_to_z_from", text="")
479                 sub.itemR(con, "to_min_z", text="")
480                 sub.itemR(con, "to_max_z", text="")
481                 
482                 self.space_template(layout, con)
483                 
484         def SHRINKWRAP (self, layout, con):
485                 self.target_template(layout, con)
486                 
487                 layout.itemR(con, "distance")
488                 layout.itemR(con, "shrinkwrap_type")
489                 
490                 if con.shrinkwrap_type == 'PROJECT':
491                         row = layout.row(align=True)
492                         row.itemR(con, "axis_x")
493                         row.itemR(con, "axis_y")
494                         row.itemR(con, "axis_z")
495                 
496 class OBJECT_PT_constraints(ConstraintButtonsPanel):
497         __label__ = "Constraints"
498         __context__ = "constraint"
499
500         def poll(self, context):
501                 return (context.object)
502                 
503         def draw(self, context):
504                 layout = self.layout
505                 ob = context.object
506
507                 row = layout.row()
508                 row.item_menu_enumO("object.constraint_add", "type")
509                 row.itemL();
510
511                 for con in ob.constraints:
512                         self.draw_constraint(con)
513
514 class BONE_PT_constraints(ConstraintButtonsPanel):
515         __label__ = "Constraints"
516         __context__ = "bone_constraint"
517
518         def poll(self, context):
519                 ob = context.object
520                 return (ob and ob.type == 'ARMATURE' and context.bone)
521                 
522         def draw(self, context):
523                 layout = self.layout
524                 
525                 ob = context.object
526                 pchan = ob.pose.pose_channels[context.bone.name]
527
528                 row = layout.row()
529                 row.item_menu_enumO("pose.constraint_add", "type")
530                 row.itemL();
531
532                 for con in pchan.constraints:
533                         self.draw_constraint(con)
534
535 bpy.types.register(OBJECT_PT_constraints)
536 bpy.types.register(BONE_PT_constraints)