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