Moving classes to separate listing broke panel order
[blender-staging.git] / release / scripts / startup / bl_ui / properties_object.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 from bpy.types import Panel, Menu
22 from rna_prop_ui import PropertyPanel
23
24
25 class ObjectButtonsPanel:
26     bl_space_type = 'PROPERTIES'
27     bl_region_type = 'WINDOW'
28     bl_context = "object"
29
30
31 class OBJECT_PT_context_object(ObjectButtonsPanel, Panel):
32     bl_label = ""
33     bl_options = {'HIDE_HEADER'}
34
35     def draw(self, context):
36         layout = self.layout
37         space = context.space_data
38
39         if space.use_pin_id:
40             layout.template_ID(space, "pin_id")
41         else:
42             row = layout.row()
43             row.template_ID(context.scene.objects, "active")
44
45
46 class OBJECT_PT_transform(ObjectButtonsPanel, Panel):
47     bl_label = "Transform"
48
49     def draw(self, context):
50         layout = self.layout
51
52         ob = context.object
53
54         row = layout.row()
55
56         row.column().prop(ob, "location")
57         if ob.rotation_mode == 'QUATERNION':
58             row.column().prop(ob, "rotation_quaternion", text="Rotation")
59         elif ob.rotation_mode == 'AXIS_ANGLE':
60             #row.column().label(text="Rotation")
61             #row.column().prop(pchan, "rotation_angle", text="Angle")
62             #row.column().prop(pchan, "rotation_axis", text="Axis")
63             row.column().prop(ob, "rotation_axis_angle", text="Rotation")
64         else:
65             row.column().prop(ob, "rotation_euler", text="Rotation")
66
67         row.column().prop(ob, "scale")
68
69         layout.prop(ob, "rotation_mode")
70
71
72 class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel):
73     bl_label = "Delta Transform"
74     bl_options = {'DEFAULT_CLOSED'}
75
76     def draw(self, context):
77         layout = self.layout
78
79         ob = context.object
80
81         row = layout.row()
82
83         row.column().prop(ob, "delta_location")
84         if ob.rotation_mode == 'QUATERNION':
85             row.column().prop(ob, "delta_rotation_quaternion", text="Rotation")
86         elif ob.rotation_mode == 'AXIS_ANGLE':
87             #row.column().label(text="Rotation")
88             #row.column().prop(pchan, "delta_rotation_angle", text="Angle")
89             #row.column().prop(pchan, "delta_rotation_axis", text="Axis")
90             #row.column().prop(ob, "delta_rotation_axis_angle", text="Rotation")
91             row.column().label(text="Not for Axis-Angle")
92         else:
93             row.column().prop(ob, "delta_rotation_euler", text="Delta Rotation")
94
95         row.column().prop(ob, "delta_scale")
96
97
98 class OBJECT_PT_transform_locks(ObjectButtonsPanel, Panel):
99     bl_label = "Transform Locks"
100     bl_options = {'DEFAULT_CLOSED'}
101
102     def draw(self, context):
103         layout = self.layout
104
105         ob = context.object
106
107         split = layout.split(percentage=0.1)
108
109         col = split.column(align=True)
110         col.label(text="")
111         col.label(text="X:")
112         col.label(text="Y:")
113         col.label(text="Z:")
114
115         split.column().prop(ob, "lock_location", text="Location")
116         split.column().prop(ob, "lock_rotation", text="Rotation")
117         split.column().prop(ob, "lock_scale", text="Scale")
118
119         if ob.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}:
120             row = layout.row()
121             row.prop(ob, "lock_rotations_4d", text="Lock Rotation")
122
123             sub = row.row()
124             sub.active = ob.lock_rotations_4d
125             sub.prop(ob, "lock_rotation_w", text="W")
126
127
128 class OBJECT_PT_relations(ObjectButtonsPanel, Panel):
129     bl_label = "Relations"
130
131     def draw(self, context):
132         layout = self.layout
133
134         ob = context.object
135
136         split = layout.split()
137
138         col = split.column()
139         col.prop(ob, "layers")
140         col.separator()
141         col.prop(ob, "pass_index")
142
143         col = split.column()
144         col.label(text="Parent:")
145         col.prop(ob, "parent", text="")
146
147         sub = col.column()
148         sub.prop(ob, "parent_type", text="")
149         parent = ob.parent
150         if parent and ob.parent_type == 'BONE' and parent.type == 'ARMATURE':
151             sub.prop_search(ob, "parent_bone", parent.data, "bones", text="")
152         sub.active = (parent is not None)
153
154
155 class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel):
156     bl_label = "Relations Extras"
157     bl_options = {'DEFAULT_CLOSED'}
158
159     def draw(self, context):
160         layout = self.layout
161
162         ob = context.object
163
164         split = layout.split()
165
166         if context.scene.render.engine != 'BLENDER_GAME':
167             col = split.column()
168             col.label(text="Tracking Axes:")
169             col.prop(ob, "track_axis", text="Axis")
170             col.prop(ob, "up_axis", text="Up Axis")
171
172         col = split.column()
173         col.prop(ob, "use_slow_parent")
174         row = col.row()
175         row.active = ((ob.parent is not None) and (ob.use_slow_parent))
176         row.prop(ob, "slow_parent_offset", text="Offset")
177
178         layout.prop(ob, "use_extra_recalc_object")
179         layout.prop(ob, "use_extra_recalc_data")
180
181
182 class GROUP_MT_specials(Menu):
183     bl_label = "Group Specials"
184
185     def draw(self, context):
186         layout = self.layout
187
188         layout.operator("object.group_unlink", icon='X')
189         layout.operator("object.grouped_select")
190         layout.operator("object.dupli_offset_from_cursor")
191
192
193 class OBJECT_PT_groups(ObjectButtonsPanel, Panel):
194     bl_label = "Groups"
195
196     def draw(self, context):
197         layout = self.layout
198
199         obj = context.object
200
201         row = layout.row(align=True)
202         if bpy.data.groups:
203             row.operator("object.group_link", text="Add to Group")
204         else:
205             row.operator("object.group_add", text="Add to Group")
206         row.operator("object.group_add", text="", icon='ZOOMIN')
207
208         obj_name = obj.name
209         for group in bpy.data.groups:
210             # XXX this is slow and stupid!, we need 2 checks, one thats fast
211             # and another that we can be sure its not a name collision
212             # from linked library data
213             group_objects = group.objects
214             if obj_name in group.objects and obj in group_objects[:]:
215                 col = layout.column(align=True)
216
217                 col.context_pointer_set("group", group)
218
219                 row = col.box().row()
220                 row.prop(group, "name", text="")
221                 row.operator("object.group_remove", text="", icon='X', emboss=False)
222                 row.menu("GROUP_MT_specials", icon='DOWNARROW_HLT', text="")
223
224                 split = col.box().split()
225
226                 col = split.column()
227                 col.prop(group, "layers", text="Dupli Visibility")
228
229                 col = split.column()
230                 col.prop(group, "dupli_offset", text="")
231
232
233 class OBJECT_PT_display(ObjectButtonsPanel, Panel):
234     bl_label = "Display"
235
236     def draw(self, context):
237         layout = self.layout
238
239         obj = context.object
240         obj_type = obj.type
241         is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'})
242         is_wire = (obj_type in {'CAMERA', 'EMPTY'})
243         is_empty_image = (obj_type == 'EMPTY' and obj.empty_draw_type == 'IMAGE')
244         is_dupli = (obj.dupli_type != 'NONE')
245
246         split = layout.split()
247
248         col = split.column()
249         col.prop(obj, "show_name", text="Name")
250         col.prop(obj, "show_axis", text="Axis")
251         # Makes no sense for cameras, armatures, etc.!
252         # but these settings do apply to dupli instances
253         if is_geometry or is_dupli:
254             col.prop(obj, "show_wire", text="Wire")
255         if obj_type == 'MESH' or is_dupli:
256             col.prop(obj, "show_all_edges")
257
258         col = split.column()
259         row = col.row()
260         row.prop(obj, "show_bounds", text="Bounds")
261         sub = row.row()
262         sub.active = obj.show_bounds
263         sub.prop(obj, "draw_bounds_type", text="")
264
265         if is_geometry:
266             col.prop(obj, "show_texture_space", text="Texture Space")
267         col.prop(obj, "show_x_ray", text="X-Ray")
268         if obj_type == 'MESH' or is_empty_image:
269             col.prop(obj, "show_transparent", text="Transparency")
270
271         split = layout.split()
272
273         col = split.column()
274         if is_wire:
275             # wire objects only use the max. draw type for duplis
276             col.active = is_dupli
277             col.label(text="Maximum Dupli Draw Type:")
278         else:
279             col.label(text="Maximum Draw Type:")
280         col.prop(obj, "draw_type", text="")
281
282         col = split.column()
283         if is_geometry or is_empty_image:
284             # Only useful with object having faces/materials...
285             col.label(text="Object Color:")
286             col.prop(obj, "color", text="")
287
288
289 class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
290     bl_label = "Duplication"
291
292     def draw(self, context):
293         layout = self.layout
294
295         ob = context.object
296
297         layout.prop(ob, "dupli_type", expand=True)
298
299         if ob.dupli_type == 'FRAMES':
300             split = layout.split()
301
302             col = split.column(align=True)
303             col.prop(ob, "dupli_frames_start", text="Start")
304             col.prop(ob, "dupli_frames_end", text="End")
305
306             col = split.column(align=True)
307             col.prop(ob, "dupli_frames_on", text="On")
308             col.prop(ob, "dupli_frames_off", text="Off")
309
310             layout.prop(ob, "use_dupli_frames_speed", text="Speed")
311
312         elif ob.dupli_type == 'VERTS':
313             layout.prop(ob, "use_dupli_vertices_rotation", text="Rotation")
314
315         elif ob.dupli_type == 'FACES':
316             row = layout.row()
317             row.prop(ob, "use_dupli_faces_scale", text="Scale")
318             sub = row.row()
319             sub.active = ob.use_dupli_faces_scale
320             sub.prop(ob, "dupli_faces_scale", text="Inherit Scale")
321
322         elif ob.dupli_type == 'GROUP':
323             layout.prop(ob, "dupli_group", text="Group")
324
325
326 from bl_ui.properties_animviz import (
327         MotionPathButtonsPanel,
328         OnionSkinButtonsPanel,
329         )
330
331
332 class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel):
333     #bl_label = "Object Motion Paths"
334     bl_context = "object"
335
336     @classmethod
337     def poll(cls, context):
338         return (context.object)
339
340     def draw(self, context):
341         # layout = self.layout
342
343         ob = context.object
344         avs = ob.animation_visualization
345         mpath = ob.motion_path
346
347         self.draw_settings(context, avs, mpath)
348
349
350 class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel):  # , Panel): # inherit from panel when ready
351     #bl_label = "Object Onion Skinning"
352     bl_context = "object"
353
354     @classmethod
355     def poll(cls, context):
356         return (context.object)
357
358     def draw(self, context):
359         ob = context.object
360
361         self.draw_settings(context, ob.animation_visualization)
362
363
364 class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel):
365     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
366     _context_path = "object"
367     _property_type = bpy.types.Object
368
369
370 classes = (
371     OBJECT_PT_context_object,
372     OBJECT_PT_transform,
373     OBJECT_PT_delta_transform,
374     OBJECT_PT_transform_locks,
375     OBJECT_PT_relations,
376     OBJECT_PT_relations_extras,
377     GROUP_MT_specials,
378     OBJECT_PT_groups,
379     OBJECT_PT_display,
380     OBJECT_PT_duplication,
381     OBJECT_PT_motion_paths,
382     OBJECT_PT_custom_props,
383 )
384
385 if __name__ == "__main__":  # only for live edit.
386     from bpy.utils import register_class
387     for cls in classes:
388         register_class(cls)