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