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