Cycles: svn merge -r40358:40411 ^/trunk/blender
[blender.git] / release / scripts / startup / bl_ui / space_dopesheet.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
21 import bpy
22 from bpy.types import Header, Menu
23 from blf import gettext as _
24
25
26 #######################################
27 # DopeSheet Filtering
28
29 # used for DopeSheet, NLA, and Graph Editors
30 def dopesheet_filter(layout, context, genericFiltersOnly=False):
31     dopesheet = context.space_data.dopesheet
32     is_nla = context.area.type == 'NLA_EDITOR'
33
34     row = layout.row(align=True)
35     row.prop(dopesheet, "show_only_selected", text="")
36     row.prop(dopesheet, "show_hidden", text="")
37
38     if is_nla:
39         row.prop(dopesheet, "show_missing_nla", text="")
40
41     if not genericFiltersOnly:
42         if bpy.data.groups:
43             row = layout.row(align=True)
44             row.prop(dopesheet, "show_only_group_objects", text="")
45             if dopesheet.show_only_group_objects:
46                 row.prop(dopesheet, "filter_group", text="")
47
48     if not is_nla:
49         row = layout.row(align=True)
50         row.prop(dopesheet, "show_only_matching_fcurves", text="")
51         if dopesheet.show_only_matching_fcurves:
52             row.prop(dopesheet, "filter_fcurve_name", text="")
53
54     if not genericFiltersOnly:
55         row = layout.row(align=True)
56         row.prop(dopesheet, "show_datablock_filters", text="Filters")
57
58         if dopesheet.show_datablock_filters:
59             row.prop(dopesheet, "show_scenes", text="")
60             row.prop(dopesheet, "show_worlds", text="")
61             row.prop(dopesheet, "show_nodes", text="")
62
63             row.prop(dopesheet, "show_transforms", text="")
64
65             if bpy.data.meshes:
66                 row.prop(dopesheet, "show_meshes", text="")
67             if bpy.data.shape_keys:
68                 row.prop(dopesheet, "show_shapekeys", text="")
69             if bpy.data.materials:
70                 row.prop(dopesheet, "show_materials", text="")
71             if bpy.data.lamps:
72                 row.prop(dopesheet, "show_lamps", text="")
73             if bpy.data.textures:
74                 row.prop(dopesheet, "show_textures", text="")
75             if bpy.data.cameras:
76                 row.prop(dopesheet, "show_cameras", text="")
77             if bpy.data.curves:
78                 row.prop(dopesheet, "show_curves", text="")
79             if bpy.data.metaballs:
80                 row.prop(dopesheet, "show_metaballs", text="")
81             if bpy.data.lattices:
82                 row.prop(dopesheet, "show_lattices", text="")
83             if bpy.data.armatures:
84                 row.prop(dopesheet, "show_armatures", text="")
85             if bpy.data.particles:
86                 row.prop(dopesheet, "show_particles", text="")
87             if bpy.data.speakers:
88                 row.prop(dopesheet, "show_speakers", text="")
89
90
91 #######################################
92 # DopeSheet Editor - General/Standard UI
93
94 class DOPESHEET_HT_header(Header):
95     bl_space_type = 'DOPESHEET_EDITOR'
96
97     def draw(self, context):
98         layout = self.layout
99
100         st = context.space_data
101
102         row = layout.row(align=True)
103         row.template_header()
104
105         if context.area.show_menus:
106             row.menu("DOPESHEET_MT_view")
107             row.menu("DOPESHEET_MT_select")
108             row.menu("DOPESHEET_MT_marker")
109
110             if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action is not None):
111                 row.menu("DOPESHEET_MT_channel")
112             elif st.mode == 'GPENCIL':
113                 row.menu("DOPESHEET_MT_gpencil_channel")
114
115             if st.mode != 'GPENCIL':
116                 row.menu("DOPESHEET_MT_key")
117             else:
118                 row.menu("DOPESHEET_MT_gpencil_frame")
119
120         layout.prop(st, "mode", text="")
121         layout.prop(st.dopesheet, "show_summary", text=_("Summary"))
122
123         if st.mode == 'DOPESHEET':
124             dopesheet_filter(layout, context)
125         elif st.mode == 'ACTION':
126             # 'genericFiltersOnly' limits the options to only the relevant 'generic' subset of
127             # filters which will work here and are useful (especially for character animation)
128             dopesheet_filter(layout, context, genericFiltersOnly=True)
129
130         if st.mode in {'ACTION', 'SHAPEKEY'}:
131             layout.template_ID(st, "action", new="action.new")
132
133         # Grease Pencil mode doesn't need snapping, as it's frame-aligned only
134         if st.mode != 'GPENCIL':
135             layout.prop(st, "auto_snap", text="")
136
137         row = layout.row(align=True)
138         row.operator("action.copy", text="", icon='COPYDOWN')
139         row.operator("action.paste", text="", icon='PASTEDOWN')
140
141
142 class DOPESHEET_MT_view(Menu):
143     bl_label = "View"
144
145     def draw(self, context):
146         layout = self.layout
147
148         st = context.space_data
149
150         layout.prop(st, "use_realtime_update")
151         layout.prop(st, "show_frame_indicator")
152         layout.prop(st, "show_sliders")
153         layout.prop(st, "use_auto_merge_keyframes")
154         layout.prop(st, "use_marker_sync")
155
156         if st.show_seconds:
157             layout.operator("anim.time_toggle", text=_("Show Frames"))
158         else:
159             layout.operator("anim.time_toggle", text=_("Show Seconds"))
160
161         layout.separator()
162         layout.operator("anim.previewrange_set")
163         layout.operator("anim.previewrange_clear")
164         layout.operator("action.previewrange_set")
165
166         layout.separator()
167         layout.operator("action.frame_jump")
168         layout.operator("action.view_all")
169         layout.operator("action.view_selected")
170
171         layout.separator()
172         layout.operator("screen.area_dupli")
173         layout.operator("screen.screen_full_area")
174
175
176 class DOPESHEET_MT_select(Menu):
177     bl_label = "Select"
178
179     def draw(self, context):
180         layout = self.layout
181
182         # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None
183         layout.operator("action.select_all_toggle")
184         layout.operator("action.select_all_toggle", text=_("Invert Selection")).invert = True
185
186         layout.separator()
187         layout.operator("action.select_border")
188         layout.operator("action.select_border", text=_("Border Axis Range")).axis_range = True
189
190         layout.separator()
191         layout.operator("action.select_column", text=_("Columns on Selected Keys")).mode = 'KEYS'
192         layout.operator("action.select_column", text=_("Column on Current Frame")).mode = 'CFRA'
193
194         layout.operator("action.select_column", text=_("Columns on Selected Markers")).mode = 'MARKERS_COLUMN'
195         layout.operator("action.select_column", text=_("Between Selected Markers")).mode = 'MARKERS_BETWEEN'
196
197         layout.separator()
198         layout.operator("action.select_leftright", text=_("Before Current Frame")).mode = 'LEFT'
199         layout.operator("action.select_leftright", text=_("After Current Frame")).mode = 'RIGHT'
200
201         # FIXME: grease pencil mode isn't supported for these yet, so skip for that mode only
202         if context.space_data.mode != 'GPENCIL':
203             layout.separator()
204             layout.operator("action.select_more")
205             layout.operator("action.select_less")
206
207             layout.separator()
208             layout.operator("action.select_linked")
209
210
211 class DOPESHEET_MT_marker(Menu):
212     bl_label = "Marker"
213
214     def draw(self, context):
215         layout = self.layout
216
217         st = context.space_data
218
219         #layout.operator_context = 'EXEC_REGION_WIN'
220
221         layout.operator("marker.add", _("Add Marker"))
222         layout.operator("marker.duplicate", text=_("Duplicate Marker"))
223         layout.operator("marker.delete", text=_("Delete Marker"))
224
225         layout.separator()
226
227         layout.operator("marker.rename", text=_("Rename Marker"))
228         layout.operator("marker.move", text=_("Grab/Move Marker"))
229
230         if st.mode in {'ACTION', 'SHAPEKEY'} and st.action:
231             layout.separator()
232             layout.prop(st, "show_pose_markers")
233
234             if st.show_pose_markers is False:
235                 layout.operator("action.markers_make_local")
236
237
238 #######################################
239 # Keyframe Editing
240
241 class DOPESHEET_MT_channel(Menu):
242     bl_label = "Channel"
243
244     def draw(self, context):
245         layout = self.layout
246
247         layout.operator_context = 'INVOKE_REGION_CHANNELS'
248
249         layout.operator("anim.channels_delete")
250
251         layout.separator()
252         layout.operator("anim.channels_setting_toggle")
253         layout.operator("anim.channels_setting_enable")
254         layout.operator("anim.channels_setting_disable")
255
256         layout.separator()
257         layout.operator("anim.channels_editable_toggle")
258         layout.operator_menu_enum("action.extrapolation_type", "type", text=_("Extrapolation Mode"))
259
260         layout.separator()
261         layout.operator("anim.channels_expand")
262         layout.operator("anim.channels_collapse")
263
264         layout.separator()
265         layout.operator_menu_enum("anim.channels_move", "direction", text=_("Move..."))
266
267         layout.separator()
268         layout.operator("anim.channels_fcurves_enable")
269
270
271 class DOPESHEET_MT_key(Menu):
272     bl_label = "Key"
273
274     def draw(self, context):
275         layout = self.layout
276
277         layout.menu("DOPESHEET_MT_key_transform", text=_("Transform"))
278
279         layout.operator_menu_enum("action.snap", "type", text=_("Snap"))
280         layout.operator_menu_enum("action.mirror", "type", text=_("Mirror"))
281
282         layout.separator()
283         layout.operator("action.keyframe_insert")
284
285         layout.separator()
286         layout.operator("action.duplicate_move")
287         layout.operator("action.delete")
288
289         layout.separator()
290         layout.operator_menu_enum("action.keyframe_type", "type", text=_("Keyframe Type"))
291         layout.operator_menu_enum("action.handle_type", "type", text=_("Handle Type"))
292         layout.operator_menu_enum("action.interpolation_type", "type", text=_("Interpolation Mode"))
293
294         layout.separator()
295         layout.operator("action.clean")
296         layout.operator("action.sample")
297
298         layout.separator()
299         layout.operator("action.copy")
300         layout.operator("action.paste")
301
302
303 class DOPESHEET_MT_key_transform(Menu):
304     bl_label = "Transform"
305
306     def draw(self, context):
307         layout = self.layout
308
309         layout.operator("transform.transform", text=_("Grab/Move")).mode = 'TIME_TRANSLATE'
310         layout.operator("transform.transform", text=_("Extend")).mode = 'TIME_EXTEND'
311         layout.operator("transform.transform", text=_("Slide")).mode = 'TIME_SLIDE'
312         layout.operator("transform.transform", text=_("Scale")).mode = 'TIME_SCALE'
313
314
315 #######################################
316 # Grease Pencil Editing
317
318 class DOPESHEET_MT_gpencil_channel(Menu):
319     bl_label = "Channel"
320
321     def draw(self, context):
322         layout = self.layout
323
324         layout.operator_context = 'INVOKE_REGION_CHANNELS'
325
326         layout.operator("anim.channels_delete")
327
328         layout.separator()
329         layout.operator("anim.channels_setting_toggle")
330         layout.operator("anim.channels_setting_enable")
331         layout.operator("anim.channels_setting_disable")
332
333         layout.separator()
334         layout.operator("anim.channels_editable_toggle")
335
336         # XXX: to be enabled when these are ready for use!
337         #layout.separator()
338         #layout.operator("anim.channels_expand")
339         #layout.operator("anim.channels_collapse")
340
341         #layout.separator()
342         #layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
343
344
345 class DOPESHEET_MT_gpencil_frame(Menu):
346     bl_label = "Frame"
347
348     def draw(self, context):
349         layout = self.layout
350
351         layout.menu("DOPESHEET_MT_key_transform", text=_("Transform"))
352
353         #layout.operator_menu_enum("action.snap", "type", text="Snap")
354         #layout.operator_menu_enum("action.mirror", "type", text="Mirror")
355
356         layout.separator()
357         layout.operator("action.duplicate")
358         layout.operator("action.delete")
359
360         #layout.separator()
361         #layout.operator("action.copy")
362         #layout.operator("action.paste")
363
364 if __name__ == "__main__":  # only for live edit.
365     bpy.utils.register_module(__name__)