fbd49cb764018905aa1601d12368ba342b512772
[blender.git] / release / scripts / startup / bl_ui / space_sequencer.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 Header, Menu, Panel
22 from bpy.app.translations import contexts as i18n_contexts
23 from rna_prop_ui import PropertyPanel
24 from .properties_grease_pencil_common import (
25     AnnotationDataPanel,
26     AnnotationOnionSkin,
27     GreasePencilToolsPanel,
28 )
29 from bpy.app.translations import pgettext_iface as iface_
30
31
32 def act_strip(context):
33     try:
34         return context.scene.sequence_editor.active_strip
35     except AttributeError:
36         return None
37
38
39 def selected_sequences_len(context):
40     selected_sequences = getattr(context, "selected_sequences", None)
41     if selected_sequences is None:
42         return 0
43     return len(selected_sequences)
44
45
46 def draw_color_balance(layout, color_balance):
47
48     layout.use_property_split = False
49
50     flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
51     col = flow.column()
52
53     box = col.box()
54     split = box.split(factor=0.35)
55     col = split.column(align=True)
56     col.label(text="Lift:")
57     col.separator()
58     col.separator()
59     col.prop(color_balance, "lift", text="")
60     col.prop(color_balance, "invert_lift", text="Invert", icon='ARROW_LEFTRIGHT')
61     split.template_color_picker(color_balance, "lift", value_slider=True, cubic=True)
62
63     col = flow.column()
64
65     box = col.box()
66     split = box.split(factor=0.35)
67     col = split.column(align=True)
68     col.label(text="Gamma:")
69     col.separator()
70     col.separator()
71     col.prop(color_balance, "gamma", text="")
72     col.prop(color_balance, "invert_gamma", text="Invert", icon='ARROW_LEFTRIGHT')
73     split.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True)
74
75     col = flow.column()
76
77     box = col.box()
78     split = box.split(factor=0.35)
79     col = split.column(align=True)
80     col.label(text="Gain:")
81     col.separator()
82     col.separator()
83     col.prop(color_balance, "gain", text="")
84     col.prop(color_balance, "invert_gain", text="Invert", icon='ARROW_LEFTRIGHT')
85     split.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)
86
87
88 class SEQUENCER_HT_header(Header):
89     bl_space_type = 'SEQUENCE_EDITOR'
90
91     def draw(self, context):
92         layout = self.layout
93
94         st = context.space_data
95         scene = context.scene
96
97         layout.template_header()
98
99         layout.prop(st, "view_type", text="")
100
101         SEQUENCER_MT_editor_menus.draw_collapsible(context, layout)
102
103         layout.separator_spacer()
104
105         layout.template_running_jobs()
106
107         if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
108             layout.separator()
109             layout.operator("sequencer.refresh_all", icon='FILE_REFRESH', text="")
110
111         if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
112             layout.prop(st, "display_mode", text="", icon_only=True)
113
114         if st.view_type != 'SEQUENCER':
115             layout.prop(st, "preview_channels", text="", icon_only=True)
116
117         if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
118             gpd = context.gpencil_data
119             tool_settings = context.tool_settings
120
121             # Proportional editing
122             if gpd and gpd.use_stroke_edit_mode:
123                 row = layout.row(align=True)
124                 row.prop(tool_settings, "use_proportional_edit", icon_only=True)
125                 if tool_settings.use_proportional_edit:
126                     row.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
127
128
129 class SEQUENCER_MT_editor_menus(Menu):
130     bl_idname = "SEQUENCER_MT_editor_menus"
131     bl_label = ""
132
133     def draw(self, context):
134         layout = self.layout
135         st = context.space_data
136
137         layout.menu("SEQUENCER_MT_view")
138
139         if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
140             layout.menu("SEQUENCER_MT_select")
141             layout.menu("SEQUENCER_MT_marker")
142             layout.menu("SEQUENCER_MT_add")
143             layout.menu("SEQUENCER_MT_strip")
144
145
146 class SEQUENCER_MT_view_toggle(Menu):
147     bl_label = "View Type"
148
149     def draw(self, _context):
150         layout = self.layout
151
152         layout.operator("sequencer.view_toggle").type = 'SEQUENCER'
153         layout.operator("sequencer.view_toggle").type = 'PREVIEW'
154         layout.operator("sequencer.view_toggle").type = 'SEQUENCER_PREVIEW'
155
156
157 class SEQUENCER_MT_view_cache(Menu):
158     bl_label = "Cache"
159
160     def draw(self, context):
161         layout = self.layout
162
163         ed = context.scene.sequence_editor
164         layout.prop(ed, "show_cache")
165         layout.separator()
166
167         col = layout.column()
168         col.enabled = ed.show_cache
169
170         col.prop(ed, "show_cache_final_out")
171         col.prop(ed, "show_cache_raw")
172         col.prop(ed, "show_cache_preprocessed")
173         col.prop(ed, "show_cache_composite")
174
175
176 class SEQUENCER_MT_range(Menu):
177     bl_label = "Range"
178
179     def draw(self, context):
180         layout = self.layout
181
182         layout.operator("anim.previewrange_set", text = "Set Preview Range")
183         layout.operator("anim.previewrange_clear", text = "Clear Preview Range")
184
185         layout.separator()
186
187         layout.operator("anim.start_frame_set", text = "Set Start Frame")
188         layout.operator("anim.end_frame_set", text = "Set End Frame")
189
190
191 class SEQUENCER_MT_view(Menu):
192     bl_label = "View"
193
194     def draw(self, context):
195         layout = self.layout
196
197         st = context.space_data
198         is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
199         is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}
200
201         if st.view_type == 'PREVIEW':
202             # Specifying the REGION_PREVIEW context is needed in preview-only
203             # mode, else the lookup for the shortcut will fail in
204             # wm_keymap_item_find_props() (see #32595).
205             layout.operator_context = 'INVOKE_REGION_PREVIEW'
206         layout.prop(st, "show_region_ui")
207         layout.operator_context = 'INVOKE_DEFAULT'
208
209         if st.view_type == 'SEQUENCER':
210             layout.prop(st, "show_backdrop", text="Preview as Backdrop")
211
212         layout.separator()
213
214         if is_sequencer_view:
215             layout.operator_context = 'INVOKE_REGION_WIN'
216             layout.operator("sequencer.view_selected", text="Frame Selected")
217             layout.operator("sequencer.view_all", text="Frame All")
218             layout.operator("view2d.zoom_border", text = "Zoom")
219
220             layout.separator()
221
222             layout.operator_context = 'INVOKE_DEFAULT'
223             #layout.menu("SEQUENCER_MT_frame")
224             layout.menu("SEQUENCER_MT_navigation")
225             layout.menu("SEQUENCER_MT_range")
226
227             layout.separator()
228
229         if is_preview:
230             layout.operator_context = 'INVOKE_REGION_PREVIEW'
231             layout.operator("sequencer.view_all_preview", text="Fit Preview in window")
232             layout.operator("view2d.zoom_border", text = "Zoom")
233
234             layout.separator()
235
236             ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
237
238             for a, b in ratios:
239                 layout.operator(
240                     "sequencer.view_zoom_ratio",
241                     text=iface_("Zoom %d:%d") % (a, b),
242                     translate=False,
243                 ).ratio = a / b
244
245             layout.separator()
246
247             layout.operator_context = 'INVOKE_DEFAULT'
248
249             # # XXX, invokes in the header view
250             # layout.operator("sequencer.view_ghost_border", text="Overlay Border")
251
252         if is_sequencer_view:
253             layout.prop(st, "show_seconds")
254             layout.prop(st, "show_frame_indicator")
255             layout.prop(st, "show_strip_offset")
256             layout.prop(st, "show_marker_lines")
257
258             layout.separator()
259
260             layout.menu("SEQUENCER_MT_view_cache")
261             layout.prop_menu_enum(st, "waveform_display_type")
262
263         if is_preview:
264             if st.display_mode == 'IMAGE':
265                 layout.prop(st, "show_safe_areas")
266                 layout.prop(st, "show_metadata")
267             elif st.display_mode == 'WAVEFORM':
268                 layout.prop(st, "show_separate_color")
269
270         layout.separator()
271
272         layout.operator("render.opengl", text="Sequence Render Image", icon='RENDER_STILL').sequencer = True
273         props = layout.operator("render.opengl", text="Sequence Render Animation", icon='RENDER_ANIMATION')
274         props.animation = True
275         props.sequencer = True
276
277         layout.separator()
278
279         layout.menu("INFO_MT_area")
280
281
282 class SEQUENCER_MT_select_handle(Menu):
283     bl_label = "Select Handle"
284
285     def draw(self, context):
286         layout = self.layout
287
288         layout.operator("sequencer.select_handles", text="Left").side = 'LEFT'
289         layout.operator("sequencer.select_handles", text="Right").side = 'RIGHT'
290         layout.operator("sequencer.select_handles", text="Both").side = 'BOTH'
291
292
293 class SEQUENCER_MT_select_channel(Menu):
294     bl_label = "Select Channel"
295
296     def draw(self, context):
297         layout = self.layout
298
299         layout.operator("sequencer.select_active_side", text="Left").side = 'LEFT'
300         layout.operator("sequencer.select_active_side", text="Right").side = 'RIGHT'
301
302
303 class SEQUENCER_MT_select_linked(Menu):
304     bl_label = "Select Linked"
305
306     def draw(self, context):
307         layout = self.layout
308
309         layout.operator("sequencer.select_linked", text = "All")
310         layout.operator("sequencer.select_less", text = "Less")
311         layout.operator("sequencer.select_more", text = "More")
312
313 class SEQUENCER_MT_select_playhead(Menu):
314     bl_label = "Select Playhead"
315
316     def draw(self, context):
317         layout = self.layout
318         props = layout.operator("sequencer.select", text="Left")
319         props.left_right = 'LEFT'
320         props.linked_time = True
321         props = layout.operator("sequencer.select", text="Right")
322         props.left_right = 'RIGHT'
323         props.linked_time = True
324
325
326 class SEQUENCER_MT_select(Menu):
327     bl_label = "Select"
328
329     def draw(self, _context):
330         layout = self.layout
331
332         layout.operator("sequencer.select_all", text="All").action = 'SELECT'
333         layout.operator("sequencer.select_all", text="None").action = 'DESELECT'
334         layout.operator("sequencer.select_all", text="Invert").action = 'INVERT'
335
336         layout.separator()
337
338         layout.operator("sequencer.select_box", text = "Box Select")
339
340         layout.separator()
341
342         layout.menu("SEQUENCER_MT_select_playhead", text ="Playhead")
343         layout.menu("SEQUENCER_MT_select_handle", text ="Handle")
344         layout.menu("SEQUENCER_MT_select_channel", text ="Channel")
345         layout.menu("SEQUENCER_MT_select_linked", text ="Linked")
346
347         layout.separator()
348         layout.operator_menu_enum("sequencer.select_grouped", "type", text="Grouped")
349
350
351 class SEQUENCER_MT_marker(Menu):
352     bl_label = "Marker"
353
354     def draw(self, context):
355         layout = self.layout
356
357         st = context.space_data
358         is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}
359
360         from .space_time import marker_menu_generic
361         marker_menu_generic(layout, context)
362
363         if is_sequencer_view:
364             layout.prop(st, "use_marker_sync")
365
366
367 class SEQUENCER_MT_change(Menu):
368     bl_label = "Change"
369
370     def draw(self, context):
371         layout = self.layout
372         strip = act_strip(context)
373
374         layout.operator_context = 'INVOKE_REGION_WIN'
375
376         layout.operator_menu_enum("sequencer.change_effect_input", "swap")
377         layout.operator_menu_enum("sequencer.change_effect_type", "type")
378         prop = layout.operator("sequencer.change_path", text="Path/Files")
379
380         if strip:
381             stype = strip.type
382
383             if stype == 'IMAGE':
384                 prop.filter_image = True
385             elif stype == 'MOVIE':
386                 prop.filter_movie = True
387             elif stype == 'SOUND':
388                 prop.filter_sound = True
389
390
391 class SEQUENCER_MT_navigation(Menu):
392     bl_label = "Navigation"
393
394     def draw(self, context):
395         layout = self.layout
396
397         layout.operator("screen.animation_play")
398
399         layout.separator()
400
401         layout.operator("sequencer.view_frame", text="Go to Playhead")
402
403         layout.separator()
404
405         props = layout.operator("sequencer.strip_jump", text="Jump to Previous Strip")
406         props.next = False
407         props.center = False
408         props = layout.operator("sequencer.strip_jump", text="Jump to Next Strip")
409         props.next = True
410         props.center = False
411
412         layout.separator()
413
414         props = layout.operator("sequencer.strip_jump", text="Jump to Previous Strip (Center)")
415         props.next = False
416         props.center = True
417         props = layout.operator("sequencer.strip_jump", text="Jump to Next Strip (Center)")
418         props.next = True
419         props.center = True
420
421
422 class SEQUENCER_MT_add(Menu):
423     bl_label = "Add"
424     bl_translation_context = i18n_contexts.operator_default
425
426     def draw(self, context):
427
428         layout = self.layout
429         layout.operator_context = 'INVOKE_REGION_WIN'
430
431         bpy_data_scenes_len = len(bpy.data.scenes)
432         if bpy_data_scenes_len > 10:
433             layout.operator_context = 'INVOKE_DEFAULT'
434             layout.operator("sequencer.scene_strip_add", text="Scene...", icon='SCENE_DATA')
435         elif bpy_data_scenes_len > 1:
436             layout.operator_menu_enum("sequencer.scene_strip_add", "scene", text="Scene", icon='SCENE_DATA')
437         else:
438             layout.menu("SEQUENCER_MT_add_empty", text="Scene", icon='SCENE_DATA')
439         del bpy_data_scenes_len
440
441         bpy_data_movieclips_len = len(bpy.data.movieclips)
442         if bpy_data_movieclips_len > 10:
443             layout.operator_context = 'INVOKE_DEFAULT'
444             layout.operator("sequencer.movieclip_strip_add", text="Clip...", icon='TRACKER')
445         elif bpy_data_movieclips_len > 0:
446             layout.operator_menu_enum("sequencer.movieclip_strip_add", "clip", text="Clip", icon='TRACKER')
447         else:
448             layout.menu("SEQUENCER_MT_add_empty", text="Clip", icon='TRACKER')
449         del bpy_data_movieclips_len
450
451         bpy_data_masks_len = len(bpy.data.masks)
452         if bpy_data_masks_len > 10:
453             layout.operator_context = 'INVOKE_DEFAULT'
454             layout.operator("sequencer.mask_strip_add", text="Mask...", icon='MOD_MASK')
455         elif bpy_data_masks_len > 0:
456             layout.operator_menu_enum("sequencer.mask_strip_add", "mask", text="Mask", icon='MOD_MASK')
457         else:
458             layout.menu("SEQUENCER_MT_add_empty", text="Mask", icon='MOD_MASK')
459         del bpy_data_masks_len
460
461         layout.separator()
462
463         layout.operator("sequencer.movie_strip_add", text="Movie", icon='FILE_MOVIE')
464         layout.operator("sequencer.sound_strip_add", text="Sound", icon='FILE_SOUND')
465         layout.operator("sequencer.image_strip_add", text="Image/Sequence", icon='FILE_IMAGE')
466
467         layout.separator()
468
469         layout.operator_context = 'INVOKE_REGION_WIN'
470         layout.operator("sequencer.effect_strip_add", text="Color", icon='COLOR').type = 'COLOR'
471         layout.operator("sequencer.effect_strip_add", text="Text", icon='FONT_DATA').type = 'TEXT'
472
473         layout.separator()
474
475         layout.operator("sequencer.effect_strip_add", text="Adjustment Layer", icon='COLOR').type = 'ADJUSTMENT'
476
477         layout.operator_context = 'INVOKE_DEFAULT'
478         layout.menu("SEQUENCER_MT_add_effect", icon='SHADERFX')
479
480         col = layout.column()
481         col.menu("SEQUENCER_MT_add_transitions", icon='ARROW_LEFTRIGHT')
482         col.enabled = selected_sequences_len(context) >= 2
483
484
485 class SEQUENCER_MT_add_empty(Menu):
486     bl_label = "Empty"
487
488     def draw(self, _context):
489         layout = self.layout
490
491         layout.label(text="No Items Available")
492
493
494 class SEQUENCER_MT_add_transitions(Menu):
495     bl_label = "Transitions"
496
497     def draw(self, context):
498
499         layout = self.layout
500
501         col = layout.column()
502
503         col.operator("sequencer.crossfade_sounds", text="Sound Crossfade")
504
505         col.separator()
506
507         col.operator("sequencer.effect_strip_add", text="Cross").type = 'CROSS'
508         col.operator("sequencer.effect_strip_add", text="Gamma Cross").type = 'GAMMA_CROSS'
509
510         col.separator()
511
512         col.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE'
513         col.enabled = selected_sequences_len(context) >= 2
514
515
516 class SEQUENCER_MT_add_effect(Menu):
517     bl_label = "Effect Strip"
518
519     def draw(self, context):
520
521         layout = self.layout
522         layout.operator_context = 'INVOKE_REGION_WIN'
523
524         col = layout.column()
525         col.operator("sequencer.effect_strip_add", text="Add").type = 'ADD'
526         col.operator("sequencer.effect_strip_add", text="Subtract").type = 'SUBTRACT'
527         col.operator("sequencer.effect_strip_add", text="Multiply").type = 'MULTIPLY'
528         col.operator("sequencer.effect_strip_add", text="Over Drop").type = 'OVER_DROP'
529         col.operator("sequencer.effect_strip_add", text="Alpha Over").type = 'ALPHA_OVER'
530         col.operator("sequencer.effect_strip_add", text="Alpha Under").type = 'ALPHA_UNDER'
531         col.operator("sequencer.effect_strip_add", text="Color Mix").type = 'COLORMIX'
532         col.enabled = selected_sequences_len(context) >= 2
533
534         layout.separator()
535
536         layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM'
537
538         layout.separator()
539
540         col = layout.column()
541         col.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM'
542         col.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'
543
544         col.separator()
545
546         col.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW'
547         col.operator("sequencer.effect_strip_add", text="Gaussian Blur").type = 'GAUSSIAN_BLUR'
548         col.enabled = selected_sequences_len(context) != 0
549
550
551 class SEQUENCER_MT_strip_transform(Menu):
552     bl_label = "Transform"
553
554     def draw(self, _context):
555         layout = self.layout
556
557         layout.operator("transform.transform", text="Move").mode = 'TRANSLATION'
558         layout.operator("transform.transform", text="Move/Extend from Playhead").mode = 'TIME_EXTEND'
559         layout.operator("sequencer.slip", text="Slip Strip Contents")
560
561         layout.separator()
562         layout.operator("sequencer.snap")
563         layout.operator("sequencer.offset_clear")
564
565         layout.separator()
566         layout.operator_menu_enum("sequencer.swap", "side")
567
568         layout.separator()
569         layout.operator("sequencer.gap_remove").all = False
570         layout.operator("sequencer.gap_insert")
571
572
573 class SEQUENCER_MT_strip_input(Menu):
574     bl_label = "Inputs"
575
576     def draw(self, context):
577         layout = self.layout
578         strip = act_strip(context)
579
580         layout.operator("sequencer.reload", text="Reload Strips")
581         layout.operator("sequencer.reload", text="Reload Strips and Adjust Length").adjust_length = True
582         prop = layout.operator("sequencer.change_path", text="Change Path/Files")
583         layout.operator("sequencer.swap_data", text="Swap Data")
584
585         if strip:
586             stype = strip.type
587
588             if stype == 'IMAGE':
589                 prop.filter_image = True
590             elif stype == 'MOVIE':
591                 prop.filter_movie = True
592             elif stype == 'SOUND':
593                 prop.filter_sound = True
594
595
596 class SEQUENCER_MT_strip_lock_mute(Menu):
597     bl_label = "Lock/Mute"
598
599     def draw(self, _context):
600         layout = self.layout
601
602         layout.operator("sequencer.lock", icon='LOCKED')
603         layout.operator("sequencer.unlock")
604
605         layout.separator()
606
607         layout.operator("sequencer.mute").unselected = False
608         layout.operator("sequencer.unmute").unselected = False
609         layout.operator("sequencer.mute", text="Mute Unselected Strips").unselected = True
610         layout.operator("sequencer.unmute", text="Unmute Deselected Strips").unselected = True
611
612
613 class SEQUENCER_MT_strip(Menu):
614     bl_label = "Strip"
615
616     def draw(self, context):
617         layout = self.layout
618
619         layout.operator_context = 'INVOKE_REGION_WIN'
620
621         layout.separator()
622         layout.menu("SEQUENCER_MT_strip_transform")
623
624         layout.separator()
625         layout.operator("sequencer.cut", text="Cut").type = 'SOFT'
626         layout.operator("sequencer.cut", text="Hold Cut").type = 'HARD'
627
628         layout.separator()
629         layout.operator("sequencer.copy", text="Copy")
630         layout.operator("sequencer.paste", text="Paste")
631         layout.operator("sequencer.duplicate_move")
632         layout.operator("sequencer.delete", text="Delete...")
633
634         layout.separator()
635         layout.menu("SEQUENCER_MT_strip_lock_mute")
636
637         strip = act_strip(context)
638
639         if strip:
640             stype = strip.type
641
642             if stype != 'SOUND':
643                 layout.separator()
644                 layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
645                 layout.operator("sequencer.strip_modifier_copy", text = "Copy Modifiers to Selection")
646
647             if stype in {
648                     'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
649                     'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'WIPE', 'GLOW',
650                     'TRANSFORM', 'COLOR', 'SPEED', 'MULTICAM', 'ADJUSTMENT',
651                     'GAUSSIAN_BLUR', 'TEXT',
652             }:
653                 layout.separator()
654                 layout.operator_menu_enum("sequencer.change_effect_input", "swap")
655                 layout.operator_menu_enum("sequencer.change_effect_type", "type")
656                 layout.operator("sequencer.reassign_inputs")
657                 layout.operator("sequencer.swap_inputs")
658             elif stype in {'IMAGE', 'MOVIE'}:
659                 layout.separator()
660                 layout.operator("sequencer.rendersize")
661                 layout.operator("sequencer.images_separate")
662                 layout.operator("sequencer.deinterlace_selected_movies")
663             elif stype == 'META':
664                 layout.separator()
665                 layout.operator("sequencer.meta_separate")
666
667         layout.separator()
668         layout.operator("sequencer.meta_make")
669         layout.operator("sequencer.meta_toggle", text="Toggle Meta")
670
671         layout.separator()
672         layout.menu("SEQUENCER_MT_strip_input")
673
674         layout.separator()
675         layout.operator("sequencer.rebuild_proxy")
676
677
678 class SEQUENCER_MT_context_menu(Menu):
679     bl_label = "Sequencer Context Menu"
680
681     def draw(self, context):
682         layout = self.layout
683
684         layout.operator_context = 'INVOKE_REGION_WIN'
685
686         layout.operator("sequencer.cut", text="Cut").type = 'SOFT'
687
688         layout.separator()
689
690         layout.operator("sequencer.copy", text="Copy", icon='COPYDOWN')
691         layout.operator("sequencer.paste", text="Paste", icon='PASTEDOWN')
692         layout.operator("sequencer.duplicate_move")
693         layout.operator("sequencer.delete", text="Delete...")
694
695         layout.separator()
696
697         layout.operator("sequencer.slip", text="Slip Strip Contents")
698         layout.operator("sequencer.snap")
699
700         layout.separator()
701
702         layout.operator("sequencer.gap_remove").all = False
703         layout.operator("sequencer.gap_insert")
704
705         strip = act_strip(context)
706
707         if strip:
708             stype = strip.type
709
710             if stype == 'META':
711                 layout.separator()
712                 layout.operator("sequencer.meta_separate")
713
714             if stype != 'SOUND':
715                 layout.separator()
716                 layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
717                 layout.operator("sequencer.strip_modifier_copy", text = "Copy Modifiers to Selection")
718
719                 if selected_sequences_len(context) >= 2:
720                     layout.separator()
721                     col = layout.column()
722                     col.menu("SEQUENCER_MT_add_transitions", text="Add Transition")
723             elif selected_sequences_len(context) >= 2:
724                 layout.separator()
725                 layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")
726
727         layout.separator()
728
729         layout.operator("sequencer.meta_make")
730         layout.operator("sequencer.meta_toggle", text="Toggle Meta")
731
732         layout.separator()
733
734         layout.menu("SEQUENCER_MT_strip_lock_mute")
735
736
737 class SequencerButtonsPanel:
738     bl_space_type = 'SEQUENCE_EDITOR'
739     bl_region_type = 'UI'
740
741     @staticmethod
742     def has_sequencer(context):
743         return (context.space_data.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'})
744
745     @classmethod
746     def poll(cls, context):
747         return cls.has_sequencer(context) and (act_strip(context) is not None)
748
749
750 class SequencerButtonsPanel_Output:
751     bl_space_type = 'SEQUENCE_EDITOR'
752     bl_region_type = 'UI'
753
754     @staticmethod
755     def has_preview(context):
756         st = context.space_data
757         return (st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}) or st.show_backdrop
758
759     @classmethod
760     def poll(cls, context):
761         return cls.has_preview(context)
762
763
764 class SEQUENCER_PT_info(SequencerButtonsPanel, Panel):
765     bl_label = "Info"
766     bl_options = {'DEFAULT_CLOSED'}
767     bl_category = "Strip"
768
769     def draw(self, context):
770         layout = self.layout
771         layout.use_property_split = True
772         layout.use_property_decorate = False
773
774         scene = context.scene
775         strip = act_strip(context)
776
777         row = layout.row(align=True)
778         row.prop(strip, "name", text=strip.type.title())
779         row.prop(strip, "lock", toggle=True, icon_only=True)
780
781
782 class SEQUENCER_PT_adjust_offset(SequencerButtonsPanel, Panel):
783     bl_label = "Offset"
784     bl_parent_id = "SEQUENCER_PT_adjust"
785     bl_options = {'DEFAULT_CLOSED'}
786     bl_category = "Strip"
787
788     @classmethod
789     def poll(cls, context):
790         strip = act_strip(context)
791         return strip.type != 'SOUND'
792
793     def draw_header(self, context):
794         strip = act_strip(context)
795         self.layout.prop(strip, "use_translation", text="")
796
797     def draw(self, context):
798         strip = act_strip(context)
799         layout = self.layout
800         layout.use_property_split = True
801         layout.use_property_decorate = False
802
803         if  strip.use_translation:
804             col = layout.column(align=True)
805             col.prop(strip.transform, "offset_x", text="Position X")
806             col.prop(strip.transform, "offset_y", text="Y")
807             col.active = strip.use_translation
808         else:
809             layout.separator()
810
811
812 class SEQUENCER_PT_adjust_crop(SequencerButtonsPanel, Panel):
813     bl_label = "Crop"
814     bl_parent_id = "SEQUENCER_PT_adjust"
815     bl_options = {'DEFAULT_CLOSED'}
816     bl_category = "Strip"
817
818     @classmethod
819     def poll(cls, context):
820         strip = act_strip(context)
821         return strip.type != 'SOUND'
822
823     def draw_header(self, context):
824         strip = act_strip(context)
825         self.layout.prop(strip, "use_crop", text="")
826
827     def draw(self, context):
828         strip = act_strip(context)
829         layout = self.layout
830         layout.use_property_split = True
831         layout.use_property_decorate = False
832
833         if strip.use_crop:
834             col = layout.column(align=True)
835             col.prop(strip.crop, "min_x")
836             col.prop(strip.crop, "max_x")
837             col.prop(strip.crop, "max_y")
838             col.prop(strip.crop, "min_y")
839         else:
840             layout.separator()
841
842
843 class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
844     bl_label = "Effect Strip"
845     bl_category = "Strip"
846
847     @classmethod
848     def poll(cls, context):
849         if not cls.has_sequencer(context):
850             return False
851
852         strip = act_strip(context)
853         if not strip:
854             return False
855
856         return strip.type in {
857             'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
858             'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
859             'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
860             'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT', 'COLORMIX'
861         }
862
863     def draw(self, context):
864         layout = self.layout
865         layout.use_property_split = True
866         layout.use_property_decorate = False
867
868         strip = act_strip(context)
869
870         if strip.input_count > 0:
871             col = layout.column()
872             col.enabled = False
873             col.prop(strip, "input_1")
874             if strip.input_count > 1:
875                 col.prop(strip, "input_2")
876
877         if strip.type == 'COLOR':
878             layout.prop(strip, "color")
879
880         elif strip.type == 'WIPE':
881             col = layout.column()
882             col.prop(strip, "transition_type")
883             col.alignment = "RIGHT"
884             col.row().prop(strip, "direction", expand=True)
885
886             col = layout.column()
887             col.prop(strip, "blur_width", slider=True)
888             if strip.transition_type in {'SINGLE', 'DOUBLE'}:
889                 col.prop(strip, "angle")
890
891         elif strip.type == 'GLOW':
892             flow = layout.column_flow()
893             flow.prop(strip, "threshold", slider=True)
894             flow.prop(strip, "clamp", slider=True)
895             flow.prop(strip, "boost_factor")
896             flow.prop(strip, "blur_radius")
897
898             row = layout.row()
899             row.prop(strip, "quality", slider=True)
900             row.prop(strip, "use_only_boost")
901
902         elif strip.type == 'SPEED':
903             layout.prop(strip, "use_default_fade", text="Stretch to input strip length")
904             if not strip.use_default_fade:
905                 layout.prop(strip, "use_as_speed")
906                 if strip.use_as_speed:
907                     layout.prop(strip, "speed_factor")
908                 else:
909                     layout.prop(strip, "speed_factor", text="Frame Number")
910                     layout.prop(strip, "use_scale_to_length")
911
912         elif strip.type == 'TRANSFORM':
913             layout = self.layout
914             col = layout.column()
915
916             col.prop(strip, "interpolation")
917             col.prop(strip, "translation_unit")
918             layout = layout.column(align=True)
919             layout.prop(strip, "translate_start_x", text="Position X")
920             layout.prop(strip, "translate_start_y", text="Y")
921
922             layout.separator()
923
924             col = layout.column(align=True)
925             col.prop(strip, "use_uniform_scale")
926             if strip.use_uniform_scale:
927                 col = layout.column(align=True)
928                 col.prop(strip, "scale_start_x", text="Scale")
929             else:
930                 layout.prop(strip, "scale_start_x", text="Scale X")
931                 layout.prop(strip, "scale_start_y", text="Y")
932
933             layout.separator()
934
935             layout.prop(strip, "rotation_start", text="Rotation")
936
937         elif strip.type == 'MULTICAM':
938             col = layout.column(align=True)
939             strip_channel = strip.channel
940
941             col.prop(strip, "multicam_source", text="Source Channel")
942
943             # The multicam strip needs at least 2 strips to be useful
944             if strip_channel > 2:
945                 BT_ROW = 4
946                 #col.alignment = "RIGHT"
947                 col.label(text="    Cut to")
948                 row = col.row()
949
950                 for i in range(1, strip_channel):
951                     if (i % BT_ROW) == 1:
952                         row = col.row(align=True)
953
954                     # Workaround - .enabled has to have a separate UI block to work
955                     if i == strip.multicam_source:
956                         sub = row.row(align=True)
957                         sub.enabled = False
958                         sub.operator("sequencer.cut_multicam", text=f"{i:d}").camera = i
959                     else:
960                         sub_1 = row.row(align=True)
961                         sub_1.enabled = True
962                         sub_1.operator("sequencer.cut_multicam", text=f"{i:d}").camera = i
963
964                 if strip.channel > BT_ROW and (strip_channel - 1) % BT_ROW:
965                     for i in range(strip.channel, strip_channel + ((BT_ROW + 1 - strip_channel) % BT_ROW)):
966                         row.label(text="")
967             else:
968                 col.separator()
969                 col.label(text="Two or more channels are needed below this strip", icon='INFO')
970
971         elif strip.type == 'TEXT':
972             col = layout.column()
973             col.prop(strip, "text")
974             col.template_ID(strip, "font", open="font.open", unlink="font.unlink")
975             col.prop(strip, "font_size")
976
977             row = col.row()
978             row.prop(strip, "color")
979             row = col.row()
980             row.prop(strip, "use_shadow")
981             rowsub = row.row()
982             rowsub.active = strip.use_shadow
983             rowsub.prop(strip, "shadow_color", text="")
984
985             col.prop(strip, "align_x")
986             col.prop(strip, "align_y", text="Y")
987             row = col.row(align=True)
988             row.prop(strip, "location", text="Location")
989             col.prop(strip, "wrap_width")
990
991             layout.operator("sequencer.export_subtitles", text="Export Subtitles", icon='EXPORT')
992
993         col = layout.column(align=True)
994         if strip.type == 'SPEED':
995             col.prop(strip, "multiply_speed")
996         elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
997             col.prop(strip, "use_default_fade", text="Default fade")
998             if not strip.use_default_fade:
999                 col.prop(strip, "effect_fader", text="Effect Fader")
1000         elif strip.type == 'GAUSSIAN_BLUR':
1001             layout = layout.column(align=True)
1002             layout.prop(strip, "size_x", text="Size X")
1003             layout.prop(strip, "size_y", text="Y")
1004         elif strip.type == 'COLORMIX':
1005             layout.prop(strip, "blend_effect", text="Blend Mode")
1006             row = layout.row(align=True)
1007             row.prop(strip, "factor", slider=True)
1008
1009
1010 class SEQUENCER_PT_info_input(SequencerButtonsPanel, Panel):
1011     bl_label = "Input"
1012     bl_parent_id = "SEQUENCER_PT_info"
1013     bl_options = {'DEFAULT_CLOSED'}
1014     bl_category = "Strip"
1015
1016     @classmethod
1017     def poll(cls, context):
1018         if not cls.has_sequencer(context):
1019             return False
1020
1021         strip = act_strip(context)
1022         if not strip:
1023             return False
1024
1025         return strip.type in {'MOVIE', 'IMAGE', 'SOUND'}
1026
1027         ''', 'SCENE', 'MOVIECLIP', 'META',
1028         'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
1029         'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
1030         'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
1031         'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX' }'''
1032
1033     def draw(self, context):
1034         layout = self.layout
1035         layout.use_property_split = True
1036         layout.use_property_decorate = False
1037
1038         st = context.space_data
1039         scene = context.scene
1040         strip = act_strip(context)
1041         seq_type = strip.type
1042
1043         # draw a filename if we have one
1044         if seq_type == 'IMAGE':
1045             layout.prop(strip, "directory", text="")
1046
1047             # Current element for the filename
1048
1049             elem = strip.strip_elem_from_frame(scene.frame_current)
1050             if elem:
1051                 layout.prop(elem, "filename", text="")  # strip.elements[0] could be a fallback
1052
1053             layout.prop(strip.colorspace_settings, "name", text="Color Space")
1054
1055             layout.prop(strip, "alpha_mode", text="Alpha")
1056             sub = layout.column(align=True)
1057             sub.operator("sequencer.change_path", text="Change Data/Files", icon='FILEBROWSER').filter_image = True
1058
1059         elif seq_type == 'MOVIE':
1060             layout.prop(strip, "filepath", text="")
1061
1062             layout.prop(strip.colorspace_settings, "name", text="Color Space")
1063
1064             layout.prop(strip, "mpeg_preseek")
1065             layout.prop(strip, "stream_index")
1066
1067         elif seq_type == 'SOUND':
1068             sound = strip.sound
1069             layout.template_ID(strip, "sound", open="sound.open")
1070             if sound is not None:
1071                 layout.prop(sound, "filepath", text="")
1072
1073                 layout.use_property_split = True
1074                 layout.use_property_decorate = False
1075
1076                 layout.alignment = 'RIGHT'
1077                 sub = layout.column(align=True)
1078                 split = sub.split(factor=0.5, align=True)
1079                 split.alignment = 'RIGHT'
1080                 if sound.packed_file:
1081                     split.label(text="Unpack")
1082                     split.operator("sound.unpack", icon='PACKAGE', text="")
1083                 else:
1084                     split.label(text="Pack")
1085                     split.operator("sound.pack", icon='UGLYPACKAGE', text="")
1086
1087                 layout.prop(sound, "use_memory_cache")
1088
1089         if scene.render.use_multiview and seq_type in {'IMAGE', 'MOVIE'}:
1090             layout.prop(strip, "use_multiview")
1091
1092             col = layout.column()
1093             col.active = strip.use_multiview
1094
1095             col.row().prop(strip, "views_format", expand=True)
1096
1097             box = col.box()
1098             box.active = strip.views_format == 'STEREO_3D'
1099             box.template_image_stereo_3d(strip.stereo_3d_format)
1100
1101
1102 class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
1103     bl_label = "Sound"
1104     bl_parent_id = ""
1105     bl_category = "Strip"
1106
1107     @classmethod
1108     def poll(cls, context):
1109         if not cls.has_sequencer(context):
1110             return False
1111
1112         strip = act_strip(context)
1113         if not strip:
1114             return False
1115
1116         return (strip.type == 'SOUND')
1117
1118     def draw(self, context):
1119         layout = self.layout
1120         layout.use_property_split = True
1121         layout.use_property_decorate = False
1122
1123         st = context.space_data
1124         strip = act_strip(context)
1125         sound = strip.sound
1126
1127         layout.template_ID(strip, "sound", open="sound.open")
1128         if sound is not None:
1129             layout.prop(sound, "filepath", text="")
1130
1131             layout.use_property_split = True
1132             layout.use_property_decorate = False
1133
1134             layout.alignment = 'RIGHT'
1135             sub = layout.column(align=True)
1136             split = sub.split(factor=0.5, align=True)
1137             split.alignment = 'RIGHT'
1138             if sound.packed_file:
1139                 split.label(text="Unpack")
1140                 split.operator("sound.unpack", icon='PACKAGE', text="")
1141             else:
1142                 split.label(text="Pack")
1143                 split.operator("sound.pack", icon='UGLYPACKAGE', text="")
1144
1145             layout.prop(sound, "use_memory_cache")
1146
1147
1148 class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
1149     bl_label = "Scene"
1150     bl_category = "Strip"
1151
1152     @classmethod
1153     def poll(cls, context):
1154         if not cls.has_sequencer(context):
1155             return False
1156
1157         strip = act_strip(context)
1158         if not strip:
1159             return False
1160
1161         return (strip.type == 'SCENE')
1162
1163     def draw(self, context):
1164         layout = self.layout
1165         layout.use_property_split = True
1166         layout.use_property_decorate = False
1167
1168         strip = act_strip(context)
1169
1170         layout.template_ID(strip, "scene")
1171
1172         scene = strip.scene
1173         layout.prop(strip, "use_sequence")
1174
1175         layout.prop(scene, "audio_volume", text="Volume")
1176
1177         if not strip.use_sequence:
1178             layout.alignment = 'RIGHT'
1179             sub = layout.column(align=True)
1180             split = sub.split(factor=0.5, align=True)
1181             split.alignment = 'RIGHT'
1182             split.label(text="Camera Override")
1183             split.template_ID(strip, "scene_camera")
1184
1185             layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil")
1186
1187         if not strip.use_sequence:
1188             if scene:
1189                 # Warning, this is not a good convention to follow.
1190                 # Expose here because setting the alpha from the 'Render' menu is very inconvenient.
1191                 # layout.label(text="Preview")
1192                 layout.prop(scene.render, "film_transparent")
1193
1194
1195 class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
1196     bl_label = "Mask"
1197     bl_category = "Strip"
1198
1199     @classmethod
1200     def poll(cls, context):
1201         if not cls.has_sequencer(context):
1202             return False
1203
1204         strip = act_strip(context)
1205         if not strip:
1206             return False
1207
1208         return (strip.type == 'MASK')
1209
1210     def draw(self, context):
1211         layout = self.layout
1212         layout.use_property_split = True
1213         layout.use_property_decorate = False
1214
1215         strip = act_strip(context)
1216
1217         layout.template_ID(strip, "mask")
1218
1219         mask = strip.mask
1220
1221         if mask:
1222             sta = mask.frame_start
1223             end = mask.frame_end
1224             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
1225
1226
1227 class SEQUENCER_PT_info_data(SequencerButtonsPanel, Panel):
1228     bl_label = "Data"
1229     bl_category = "Strip"
1230     bl_parent_id = "SEQUENCER_PT_info"
1231
1232     @classmethod
1233     def poll(cls, context):
1234         if not cls.has_sequencer(context):
1235             return False
1236
1237         strip = act_strip(context)
1238         if not strip:
1239             return False
1240
1241         return strip.type
1242
1243     def draw(self, context):
1244         layout = self.layout
1245         layout.use_property_split = False
1246         layout.use_property_decorate = False
1247
1248         scene = context.scene
1249         frame_current = scene.frame_current
1250         strip = act_strip(context)
1251
1252         length_list = (
1253             str(strip.frame_start),
1254             str(strip.frame_final_end),
1255             str(strip.frame_final_duration),
1256             str(strip.frame_offset_start),
1257             str(strip.frame_offset_end),
1258         )
1259
1260         if not isinstance(strip, bpy.types.EffectSequence):
1261             length_list = length_list + (
1262                 str(strip.animation_offset_start),
1263                 str(strip.animation_offset_end),
1264             )
1265
1266         max_length = max(len(x) for x in length_list)
1267         max_factor = (1.9 - max_length) / 30
1268
1269         sub = layout.row(align=True)
1270         sub.enabled = not strip.lock
1271         split = sub.split(factor=0.5 + max_factor)
1272         split.alignment = 'RIGHT'
1273         split.label(text='Channel')
1274         split.prop(strip, "channel", text="")
1275
1276         sub = layout.column(align=True)
1277         sub.enabled = not strip.lock
1278         split = sub.split(factor=0.5 + max_factor)
1279         split.alignment = 'RIGHT'
1280         split.label(text="Start")
1281         split.prop(strip, "frame_start", text=str(bpy.utils.smpte_from_frame(strip.frame_start)).replace(':', ' '))
1282         split = sub.split(factor=0.5 + max_factor)
1283         split.alignment = 'RIGHT'
1284         split.label(text="End")
1285         split.prop(strip, "frame_final_end", text=str(bpy.utils.smpte_from_frame(strip.frame_final_end)).replace(':', ' '))
1286         split = sub.split(factor=0.5 + max_factor)
1287         split.alignment = 'RIGHT'
1288         split.label(text="Duration")
1289         split.prop(strip, "frame_final_duration", text=str(bpy.utils.smpte_from_frame(strip.frame_final_duration)).replace(':', ' '))
1290
1291         if not isinstance(strip, bpy.types.EffectSequence):
1292             layout.alignment = 'RIGHT'
1293             sub = layout.column(align=True)
1294             split = sub.split(factor=0.5 + max_factor, align=True)
1295             split.alignment = 'RIGHT'
1296             split.label(text="Soft Trim Start")
1297             split.prop(strip, "frame_offset_start", text=str(bpy.utils.smpte_from_frame(strip.frame_offset_start)).replace(':', ' '))
1298             split = sub.split(factor=0.5+max_factor, align=True)
1299             split.alignment = 'RIGHT'
1300             split.label(text='End')
1301             split.prop(strip, "frame_offset_end", text=str(bpy.utils.smpte_from_frame(strip.frame_offset_end)).replace(':', ' '))
1302
1303             layout.alignment = 'RIGHT'
1304             sub = layout.column(align=True)
1305             split = sub.split(factor=0.5 + max_factor)
1306             split.alignment = 'RIGHT'
1307             split.label(text="Hard Trim Start")
1308             split.prop(strip, "animation_offset_start", text=str(bpy.utils.smpte_from_frame(strip.animation_offset_start)).replace(':', ' '))
1309             split = sub.split(factor=0.5 + max_factor, align=True)
1310             split.alignment = 'RIGHT'
1311             split.label(text='End')
1312             split.prop(strip, "animation_offset_end", text=str(bpy.utils.smpte_from_frame(strip.animation_offset_end)).replace(':', ' '))
1313
1314         playhead = frame_current - strip.frame_start
1315         col = layout.column(align=True)
1316         col = col.box()
1317         col.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_final_duration)
1318         split = col.split(factor=0.5 + max_factor)
1319         split.alignment = 'RIGHT'
1320         split.label(text="Playhead")
1321         split.label(text="%s:   %s" % ((bpy.utils.smpte_from_frame(playhead).replace(':', ' ')), (str(playhead))))
1322
1323         ''' Old data - anyone missing this data?
1324         col.label(text=iface_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end),
1325                   translate=False)
1326         col.label(text=iface_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end), translate=False)'''
1327
1328         elem = False
1329
1330         if strip.type == 'IMAGE':
1331             elem = strip.strip_elem_from_frame(frame_current)
1332         elif strip.type == 'MOVIE':
1333             elem = strip.elements[0]
1334
1335         if strip.type != "SOUND":
1336             split = col.split(factor=0.5 + max_factor)
1337             split.alignment = 'RIGHT'
1338             split.label(text="Resolution")
1339             if elem and elem.orig_width > 0 and elem.orig_height > 0:
1340                 split.label(text="%dx%d" % (elem.orig_width, elem.orig_height), translate=False)
1341             else:
1342                 split.label(text="None")
1343
1344         if strip.type == "SCENE":
1345             scene = strip.scene
1346
1347             if scene:
1348                 sta = scene.frame_start
1349                 end = scene.frame_end
1350                 split = col.split(factor=0.5 + max_factor)
1351                 split.alignment = 'RIGHT'
1352                 split.label(text="Original Frame Range")
1353                 split.alignment = 'LEFT'
1354                 split.label(text="%d-%d (%d)" % (sta, end, end - sta + 1), translate=False)
1355
1356
1357 class SEQUENCER_PT_adjust(SequencerButtonsPanel, Panel):
1358     bl_label = "Adjust"
1359     bl_category = "Strip"
1360
1361     def draw(self, context):
1362         pass
1363
1364
1365 class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel):
1366     bl_label = "Sound"
1367     bl_parent_id = "SEQUENCER_PT_adjust"
1368     bl_category = "Strip"
1369
1370     @classmethod
1371     def poll(cls, context):
1372         strip = act_strip(context)
1373         return strip.type == 'SOUND'
1374
1375     def draw(self, context):
1376         layout = self.layout
1377         layout.use_property_split = True
1378         layout.use_property_decorate = False
1379
1380         st = context.space_data
1381         strip = act_strip(context)
1382
1383         sound = strip.sound
1384
1385         col = layout.column()
1386
1387         row = col.row(align=True)
1388         sub = row.row(align=True)
1389         sub.active = (not strip.mute)
1390
1391         sub.prop(strip, "volume", text="Volume")
1392         sub.prop(strip, "mute", toggle=True, icon_only=True, icon='MUTE_IPO_ON')
1393
1394         col.prop(strip, "pitch")
1395         col.prop(strip, "pan")
1396
1397         if sound is not None:
1398
1399             if st.waveform_display_type == 'DEFAULT_WAVEFORMS':
1400                 col.prop(strip, "show_waveform")
1401             col.prop(sound, "use_mono")
1402
1403
1404 class SEQUENCER_PT_adjust_comp(SequencerButtonsPanel, Panel):
1405     bl_label = "Compositing"
1406     bl_parent_id = "SEQUENCER_PT_adjust"
1407     bl_category = "Strip"
1408
1409     @classmethod
1410     def poll(cls, context):
1411         strip = act_strip(context)
1412         return strip.type != 'SOUND'
1413
1414     def draw(self, context):
1415         layout = self.layout
1416         layout.use_property_split = True
1417         layout.use_property_decorate = False
1418
1419         strip = act_strip(context)
1420
1421         layout.prop(strip, "blend_type", text="Blend")
1422
1423         row = layout.row(align=True)
1424         sub = row.row(align=True)
1425         sub.active = (not strip.mute)
1426
1427         sub.prop(strip, "blend_alpha", text="Opacity", slider=True)
1428         sub.prop(strip, "mute", toggle=True, icon_only=True)
1429
1430
1431 class SEQUENCER_PT_adjust_video(SequencerButtonsPanel, Panel):
1432     bl_label = "Video"
1433     bl_parent_id = "SEQUENCER_PT_adjust"
1434     bl_options = {'DEFAULT_CLOSED'}
1435     bl_category = "Strip"
1436
1437     @classmethod
1438     def poll(cls, context):
1439         if not cls.has_sequencer(context):
1440             return False
1441
1442         strip = act_strip(context)
1443         if not strip:
1444             return False
1445
1446         return strip.type in {
1447             'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK',
1448             'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
1449             'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
1450             'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
1451             'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX'
1452         }
1453
1454     def draw(self, context):
1455         layout = self.layout
1456         layout.use_property_split = True
1457         layout.use_property_decorate = False
1458
1459         strip = act_strip(context)
1460
1461         col = layout.column()
1462         col.prop(strip, "strobe")
1463
1464         if strip.type == 'MOVIECLIP':
1465             col = layout.column()
1466             col.label(text="Tracker")
1467             col.prop(strip, "stabilize2d")
1468
1469             col = layout.column()
1470             col.label(text="Distortion")
1471             col.prop(strip, "undistort")
1472             col.separator()
1473
1474         col.prop(strip, "use_reverse_frames", text="Backwards")
1475         col.prop(strip, "use_deinterlace")
1476
1477         col.separator()
1478
1479         col.prop(strip, "use_flip_x", text="Flip X")
1480         col.prop(strip, "use_flip_y", text="Flip Y")
1481
1482
1483 class SEQUENCER_PT_adjust_color(SequencerButtonsPanel, Panel):
1484     bl_label = "Color"
1485     bl_parent_id = "SEQUENCER_PT_adjust"
1486     bl_options = {'DEFAULT_CLOSED'}
1487     bl_category = "Strip"
1488
1489     @classmethod
1490     def poll(cls, context):
1491         if not cls.has_sequencer(context):
1492             return False
1493
1494         strip = act_strip(context)
1495         if not strip:
1496             return False
1497
1498         return strip.type in {
1499             'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK',
1500             'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
1501             'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
1502             'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
1503             'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX'
1504         }
1505
1506     def draw(self, context):
1507         layout = self.layout
1508         layout.use_property_split = True
1509         layout.use_property_decorate = False
1510
1511         strip = act_strip(context)
1512
1513         col = layout.column()
1514         col.prop(strip, "color_saturation", text="Saturation")
1515         col.prop(strip, "color_multiply", text="Multiply")
1516         col.prop(strip, "use_float", text="Convert to Float")
1517
1518
1519 class SEQUENCER_PT_cache_settings(SequencerButtonsPanel, Panel):
1520     bl_label = "Cache Settings"
1521     bl_category = "Proxy & Cache"
1522
1523     @classmethod
1524     def poll(cls, context):
1525         return cls.has_sequencer(context) and context.scene.sequence_editor
1526
1527     def draw(self, context):
1528         layout = self.layout
1529         ed = context.scene.sequence_editor
1530
1531         layout.prop(ed, "use_cache_raw")
1532         layout.prop(ed, "use_cache_preprocessed")
1533         layout.prop(ed, "use_cache_composite")
1534         layout.prop(ed, "use_cache_final")
1535         layout.separator()
1536         layout.prop(ed, "recycle_max_cost")
1537
1538
1539 class SEQUENCER_PT_proxy_settings(SequencerButtonsPanel, Panel):
1540     bl_label = "Proxy Settings"
1541     bl_category = "Proxy & Cache"
1542
1543     @classmethod
1544     def poll(cls, context):
1545         return cls.has_sequencer(context) and context.scene.sequence_editor
1546
1547     def draw(self, context):
1548         layout = self.layout
1549         ed = context.scene.sequence_editor
1550         flow = layout.column_flow()
1551         flow.prop(ed, "proxy_storage", text="Storage")
1552
1553         if ed.proxy_storage == 'PROJECT':
1554             flow.prop(ed, "proxy_dir", text="Directory")
1555
1556         col = layout.column()
1557         col.operator("sequencer.enable_proxies")
1558         col.operator("sequencer.rebuild_proxy")
1559
1560
1561 class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel):
1562     bl_label = "Strip Proxy & Timecode"
1563     bl_category = "Proxy & Cache"
1564
1565     @classmethod
1566     def poll(cls, context):
1567         if not cls.has_sequencer(context) and context.scene.sequence_editor:
1568             return False
1569
1570         strip = act_strip(context)
1571         if not strip:
1572             return False
1573
1574         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'META', 'MULTICAM'}
1575
1576     def draw_header(self, context):
1577         strip = act_strip(context)
1578
1579         self.layout.prop(strip, "use_proxy", text="")
1580
1581     def draw(self, context):
1582         layout = self.layout
1583         layout.use_property_split = True
1584         layout.use_property_decorate = False
1585
1586         ed = context.scene.sequence_editor
1587
1588         strip = act_strip(context)
1589
1590         if strip.proxy:
1591             proxy = strip.proxy
1592
1593             flow = layout.column_flow()
1594             if ed.proxy_storage == 'PER_STRIP':
1595                 flow.prop(proxy, "use_proxy_custom_directory")
1596                 flow.prop(proxy, "use_proxy_custom_file")
1597
1598                 if proxy.use_proxy_custom_directory and not proxy.use_proxy_custom_file:
1599                     flow.prop(proxy, "directory")
1600                 if proxy.use_proxy_custom_file:
1601                     flow.prop(proxy, "filepath")
1602
1603             layout = layout.box()
1604             row = layout.row(align=True)
1605             row.prop(strip.proxy, "build_25")
1606             row.prop(strip.proxy, "build_75")
1607             row = layout.row(align=True)
1608             row.prop(strip.proxy, "build_50")
1609             row.prop(strip.proxy, "build_100")
1610
1611             layout = self.layout
1612             layout.use_property_split = True
1613             layout.use_property_decorate = False
1614
1615             layout.prop(proxy, "use_overwrite")
1616
1617             col = layout.column()
1618             col.prop(proxy, "quality", text="Build JPEG Quality")
1619
1620             if strip.type == 'MOVIE':
1621                 col = layout.column()
1622
1623                 col.prop(proxy, "timecode", text="Timecode Index")
1624
1625
1626 class SEQUENCER_PT_strip_cache(SequencerButtonsPanel, Panel):
1627     bl_label = "Strip Cache"
1628     bl_category = "Proxy & Cache"
1629     bl_options = {'DEFAULT_CLOSED'}
1630
1631     @classmethod
1632     def poll(cls, context):
1633         if not cls.has_sequencer(context):
1634             return False
1635         if act_strip(context) is not None:
1636             return True
1637
1638     def draw_header(self, context):
1639         strip = act_strip(context)
1640         self.layout.prop(strip, "override_cache_settings", text="")
1641
1642     def draw(self, context):
1643         layout = self.layout
1644         strip = act_strip(context)
1645         layout.active = strip.override_cache_settings
1646
1647         layout.prop(strip, "use_cache_raw")
1648         layout.prop(strip, "use_cache_preprocessed")
1649         layout.prop(strip, "use_cache_composite")
1650
1651
1652 class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
1653     bl_label = "Scene Preview/Render"
1654     bl_space_type = 'SEQUENCE_EDITOR'
1655     bl_region_type = 'UI'
1656     bl_options = {'DEFAULT_CLOSED'}
1657     bl_category = "View"
1658
1659     def draw(self, context):
1660         layout = self.layout
1661         layout.use_property_split = True
1662         layout.use_property_decorate = False
1663         render = context.scene.render
1664
1665         col = layout.column()
1666         col.prop(render, "sequencer_gl_preview", text="Preview Shading")
1667
1668         if render.sequencer_gl_preview in ['SOLID', 'WIREFRAME']:
1669             col.prop(render, "use_sequencer_override_scene_strip")
1670
1671
1672 class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
1673     bl_label = "View Settings"
1674     bl_category = "View"
1675
1676     def draw(self, context):
1677         layout = self.layout
1678         layout.use_property_split = True
1679         layout.use_property_decorate = False
1680
1681         st = context.space_data
1682
1683         col = layout.column()
1684         col.prop(st, "display_channel", text="Channel")
1685
1686         if st.display_mode == 'IMAGE':
1687             col.prop(st, "show_overexposed")
1688
1689         elif st.display_mode == 'WAVEFORM':
1690             col.prop(st, "show_separate_color")
1691
1692         col.prop(st, "proxy_render_size")
1693
1694
1695 class SEQUENCER_PT_frame_overlay(SequencerButtonsPanel_Output, Panel):
1696     bl_label = "Frame Overlay"
1697     bl_category = "View"
1698     bl_options = {'DEFAULT_CLOSED'}
1699
1700     def draw_header(self, context):
1701         scene = context.scene
1702         ed = scene.sequence_editor
1703
1704         self.layout.prop(ed, "show_overlay", text="")
1705
1706     def draw(self, context):
1707         layout = self.layout
1708         layout.use_property_split = True
1709         layout.use_property_decorate = False
1710
1711
1712         st = context.space_data
1713         scene = context.scene
1714         ed = scene.sequence_editor
1715
1716         layout.active = ed.show_overlay
1717
1718         col = layout.column()
1719         col.prop(ed, "overlay_frame", text="Frame Offset")
1720         col.prop(st, "overlay_type")
1721         col.prop(ed, "use_overlay_lock")
1722
1723
1724 class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel):
1725     bl_label = "Safe Areas"
1726     bl_options = {'DEFAULT_CLOSED'}
1727     bl_category = "View"
1728
1729     @classmethod
1730     def poll(cls, context):
1731         st = context.space_data
1732         is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
1733         return is_preview and (st.display_mode == 'IMAGE')
1734
1735     def draw_header(self, context):
1736         st = context.space_data
1737
1738         self.layout.prop(st, "show_safe_areas", text="")
1739
1740     def draw(self, context):
1741         layout = self.layout
1742         layout.use_property_split = True
1743         st = context.space_data
1744         safe_data = context.scene.safe_areas
1745
1746         layout.active = st.show_safe_areas
1747
1748         col = layout.column()
1749
1750         sub = col.column()
1751         sub.prop(safe_data, "title", slider=True)
1752         sub.prop(safe_data, "action", slider=True)
1753
1754
1755 class SEQUENCER_PT_view_safe_areas_center_cut(SequencerButtonsPanel_Output, Panel):
1756     bl_label = "Center-Cut Safe Areas"
1757     bl_parent_id = "SEQUENCER_PT_view_safe_areas"
1758     bl_options = {'DEFAULT_CLOSED'}
1759     bl_category = "View"
1760
1761     def draw_header(self, context):
1762         st = context.space_data
1763
1764         layout = self.layout
1765         layout.active = st.show_safe_areas
1766         layout.prop(st, "show_safe_center", text="")
1767
1768     def draw(self, context):
1769         layout = self.layout
1770         layout.use_property_split = True
1771         safe_data = context.scene.safe_areas
1772         st = context.space_data
1773
1774         layout.active = st.show_safe_areas and st.show_safe_center
1775
1776         col = layout.column()
1777         col.prop(safe_data, "title_center", slider=True)
1778
1779
1780 class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
1781     bl_label = "Modifiers"
1782     bl_category = "Modifiers"
1783
1784     def draw(self, context):
1785         layout = self.layout
1786         layout.use_property_split = True
1787         layout.use_property_decorate = False
1788
1789         strip = act_strip(context)
1790         ed = context.scene.sequence_editor
1791
1792         layout.prop(strip, "use_linear_modifiers")
1793
1794         layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
1795         layout.operator("sequencer.strip_modifier_copy")
1796
1797         for mod in strip.modifiers:
1798             box = layout.box()
1799
1800             row = box.row()
1801             row.prop(mod, "show_expanded", text="", emboss=False)
1802             row.prop(mod, "name", text="")
1803
1804             row.prop(mod, "mute", text="")
1805
1806             sub = row.row(align=True)
1807             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_UP')
1808             props.name = mod.name
1809             props.direction = 'UP'
1810             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_DOWN')
1811             props.name = mod.name
1812             props.direction = 'DOWN'
1813
1814             row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name
1815
1816             if mod.show_expanded:
1817                 row = box.row()
1818                 row.prop(mod, "input_mask_type", expand=True)
1819
1820                 if mod.input_mask_type == 'STRIP':
1821                     sequences_object = ed
1822                     if ed.meta_stack:
1823                         sequences_object = ed.meta_stack[-1]
1824                     box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
1825                 else:
1826                     box.prop(mod, "input_mask_id")
1827                     row = box.row()
1828                     row.prop(mod, "mask_time", expand=True)
1829
1830                 if mod.type == 'COLOR_BALANCE':
1831                     box.prop(mod, "color_multiply")
1832                     draw_color_balance(box, mod.color_balance)
1833                 elif mod.type == 'CURVES':
1834                     box.template_curve_mapping(mod, "curve_mapping", type='COLOR', show_tone=True)
1835                 elif mod.type == 'HUE_CORRECT':
1836                     box.template_curve_mapping(mod, "curve_mapping", type='HUE')
1837                 elif mod.type == 'BRIGHT_CONTRAST':
1838                     col = box.column()
1839                     col.prop(mod, "bright")
1840                     col.prop(mod, "contrast")
1841                 elif mod.type == 'WHITE_BALANCE':
1842                     col = box.column()
1843                     col.prop(mod, "white_value")
1844                 elif mod.type == 'TONEMAP':
1845                     col = box.column()
1846                     col.prop(mod, "tonemap_type")
1847                     if mod.tonemap_type == 'RD_PHOTORECEPTOR':
1848                         col.prop(mod, "intensity")
1849                         col.prop(mod, "contrast")
1850                         col.prop(mod, "adaptation")
1851                         col.prop(mod, "correction")
1852                     elif mod.tonemap_type == 'RH_SIMPLE':
1853                         col.prop(mod, "key")
1854                         col.prop(mod, "offset")
1855                         col.prop(mod, "gamma")
1856
1857
1858 class SEQUENCER_PT_grease_pencil(AnnotationDataPanel, SequencerButtonsPanel_Output, Panel):
1859     bl_space_type = 'SEQUENCE_EDITOR'
1860     bl_region_type = 'UI'
1861     bl_category = "View"
1862
1863     # NOTE: this is just a wrapper around the generic GP Panel
1864     # But, it should only show up when there are images in the preview region
1865
1866
1867 class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
1868     bl_space_type = 'SEQUENCE_EDITOR'
1869     bl_region_type = 'UI'
1870     bl_category = "View"
1871
1872     # NOTE: this is just a wrapper around the generic GP tools panel
1873     # It contains access to some essential tools usually found only in
1874     # toolbar, which doesn't exist here...
1875
1876
1877 class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
1878     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
1879     _context_path = "scene.sequence_editor.active_strip"
1880     _property_type = (bpy.types.Sequence,)
1881     bl_category = "Strip"
1882
1883
1884 classes = (
1885     SEQUENCER_MT_change,
1886     SEQUENCER_HT_header,
1887     SEQUENCER_MT_editor_menus,
1888     SEQUENCER_MT_range,
1889     SEQUENCER_MT_view,
1890     SEQUENCER_MT_view_cache,
1891     SEQUENCER_MT_view_toggle,
1892     SEQUENCER_MT_select_playhead,
1893     SEQUENCER_MT_select_handle,
1894     SEQUENCER_MT_select_channel,
1895     SEQUENCER_MT_select_linked,
1896     SEQUENCER_MT_select,
1897     SEQUENCER_MT_marker,
1898     SEQUENCER_MT_navigation,
1899     SEQUENCER_MT_add,
1900     SEQUENCER_MT_add_effect,
1901     SEQUENCER_MT_add_transitions,
1902     SEQUENCER_MT_add_empty,
1903     SEQUENCER_MT_strip,
1904     SEQUENCER_MT_strip_transform,
1905     SEQUENCER_MT_strip_input,
1906     SEQUENCER_MT_strip_lock_mute,
1907     SEQUENCER_MT_context_menu,
1908
1909     SEQUENCER_PT_adjust,
1910     SEQUENCER_PT_adjust_comp,
1911     SEQUENCER_PT_adjust_offset,
1912     SEQUENCER_PT_adjust_crop,
1913     SEQUENCER_PT_adjust_video,
1914     SEQUENCER_PT_adjust_color,
1915     SEQUENCER_PT_adjust_sound,
1916
1917     SEQUENCER_PT_info,
1918     SEQUENCER_PT_info_input,
1919     SEQUENCER_PT_info_data,
1920
1921     SEQUENCER_PT_effect,
1922     SEQUENCER_PT_scene,
1923     SEQUENCER_PT_mask,
1924
1925     SEQUENCER_PT_cache_settings,
1926     SEQUENCER_PT_strip_cache,
1927     SEQUENCER_PT_proxy_settings,
1928     SEQUENCER_PT_strip_proxy,
1929
1930     SEQUENCER_PT_custom_props,
1931
1932     SEQUENCER_PT_modifiers,
1933
1934     SEQUENCER_PT_preview,
1935     SEQUENCER_PT_view,
1936     SEQUENCER_PT_frame_overlay,
1937     SEQUENCER_PT_view_safe_areas,
1938     SEQUENCER_PT_view_safe_areas_center_cut,
1939
1940     SEQUENCER_PT_grease_pencil,
1941     SEQUENCER_PT_grease_pencil_tools,
1942 )
1943
1944 if __name__ == "__main__":  # only for live edit.
1945     from bpy.utils import register_class
1946     for cls in classes:
1947         register_class(cls)