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