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