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