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