Remove commented code
[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             layout.prop(strip, "multicam_source")
656
657             row = layout.row(align=True)
658             sub = row.row(align=True)
659             sub.scale_x = 2.0
660
661             sub.operator("screen.animation_play", text="", icon='PAUSE' if context.screen.is_animation_playing else 'PLAY')
662
663             row.label("Cut To")
664             for i in range(1, strip.channel):
665                 row.operator("sequencer.cut_multicam", text="%d" % i).camera = i
666
667         elif strip.type == 'TEXT':
668             col = layout.column()
669             col.prop(strip, "text")
670             col.prop(strip, "font_size")
671
672             row = col.row()
673             row.prop(strip, "color")
674             row = col.row()
675             row.prop(strip, "use_shadow")
676             rowsub = row.row()
677             rowsub.active = strip.use_shadow
678             rowsub.prop(strip, "shadow_color", text="")
679
680             col.prop(strip, "align_x")
681             col.prop(strip, "align_y")
682             col.prop(strip, "location")
683             col.prop(strip, "wrap_width")
684             layout.operator("sequencer.export_subtitles")
685
686         col = layout.column(align=True)
687         if strip.type == 'SPEED':
688             col.prop(strip, "multiply_speed")
689         elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
690             col.prop(strip, "use_default_fade", "Default fade")
691             if not strip.use_default_fade:
692                 col.prop(strip, "effect_fader", text="Effect fader")
693         elif strip.type == 'GAUSSIAN_BLUR':
694             col.prop(strip, "size_x")
695             col.prop(strip, "size_y")
696
697
698 class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
699     bl_label = "Strip Input"
700     bl_category = "Strip"
701
702     @classmethod
703     def poll(cls, context):
704         if not cls.has_sequencer(context):
705             return False
706
707         strip = act_strip(context)
708         if not strip:
709             return False
710
711         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'META',
712                               'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
713                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
714                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
715                               'MULTICAM', 'SPEED', 'ADJUSTMENT'}
716
717     def draw(self, context):
718         layout = self.layout
719         scene = context.scene
720
721         strip = act_strip(context)
722
723         seq_type = strip.type
724
725         # draw a filename if we have one
726         if seq_type == 'IMAGE':
727             split = layout.split(percentage=0.2)
728             split.label(text="Path:")
729             split.prop(strip, "directory", text="")
730
731             # Current element for the filename
732
733             elem = strip.strip_elem_from_frame(scene.frame_current)
734             if elem:
735                 split = layout.split(percentage=0.2)
736                 split.label(text="File:")
737                 split.prop(elem, "filename", text="")  # strip.elements[0] could be a fallback
738
739             layout.prop(strip.colorspace_settings, "name")
740             layout.prop(strip, "alpha_mode")
741
742             layout.operator("sequencer.change_path").filter_image = True
743
744         elif seq_type == 'MOVIE':
745             split = layout.split(percentage=0.2)
746             split.label(text="Path:")
747             split.prop(strip, "filepath", text="")
748
749             layout.prop(strip.colorspace_settings, "name")
750
751             layout.prop(strip, "mpeg_preseek")
752             layout.prop(strip, "stream_index")
753
754         layout.prop(strip, "use_translation", text="Image Offset")
755         if strip.use_translation:
756             col = layout.column(align=True)
757             col.prop(strip.transform, "offset_x", text="X")
758             col.prop(strip.transform, "offset_y", text="Y")
759
760         layout.prop(strip, "use_crop", text="Image Crop")
761         if strip.use_crop:
762             col = layout.column(align=True)
763             col.prop(strip.crop, "max_y")
764             col.prop(strip.crop, "min_x")
765             col.prop(strip.crop, "min_y")
766             col.prop(strip.crop, "max_x")
767
768         if not isinstance(strip, bpy.types.EffectSequence):
769             col = layout.column(align=True)
770             col.label(text="Trim Duration (hard):")
771             col.prop(strip, "animation_offset_start", text="Start")
772             col.prop(strip, "animation_offset_end", text="End")
773
774         col = layout.column(align=True)
775         col.label(text="Trim Duration (soft):")
776         col.prop(strip, "frame_offset_start", text="Start")
777         col.prop(strip, "frame_offset_end", text="End")
778
779         if scene.render.use_multiview and seq_type in {'IMAGE', 'MOVIE'}:
780             layout.prop(strip, "use_multiview")
781
782             col = layout.column()
783             col.active = strip.use_multiview
784
785             col.label(text="Views Format:")
786             col.row().prop(strip, "views_format", expand=True)
787
788             box = col.box()
789             box.active = strip.views_format == 'STEREO_3D'
790             box.template_image_stereo_3d(strip.stereo_3d_format)
791
792
793 class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
794     bl_label = "Sound"
795     bl_category = "Strip"
796
797     @classmethod
798     def poll(cls, context):
799         if not cls.has_sequencer(context):
800             return False
801
802         strip = act_strip(context)
803         if not strip:
804             return False
805
806         return (strip.type == 'SOUND')
807
808     def draw(self, context):
809         layout = self.layout
810
811         st = context.space_data
812         strip = act_strip(context)
813         sound = strip.sound
814
815         layout.template_ID(strip, "sound", open="sound.open")
816         if sound is not None:
817             layout.prop(sound, "filepath", text="")
818
819             row = layout.row()
820             if sound.packed_file:
821                 row.operator("sound.unpack", icon='PACKAGE', text="Unpack")
822             else:
823                 row.operator("sound.pack", icon='UGLYPACKAGE', text="Pack")
824
825             row.prop(sound, "use_memory_cache")
826
827             layout.prop(sound, "use_mono")
828
829         if st.waveform_draw_type == 'DEFAULT_WAVEFORMS':
830             layout.prop(strip, "show_waveform")
831
832         layout.prop(strip, "volume")
833         layout.prop(strip, "pitch")
834         layout.prop(strip, "pan")
835
836         col = layout.column(align=True)
837         col.label(text="Trim Duration (hard):")
838         col.prop(strip, "animation_offset_start", text="Start")
839         col.prop(strip, "animation_offset_end", text="End")
840
841         col = layout.column(align=True)
842         col.label(text="Trim Duration (soft):")
843         col.prop(strip, "frame_offset_start", text="Start")
844         col.prop(strip, "frame_offset_end", text="End")
845
846
847 class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
848     bl_label = "Scene"
849     bl_category = "Strip"
850
851     @classmethod
852     def poll(cls, context):
853         if not cls.has_sequencer(context):
854             return False
855
856         strip = act_strip(context)
857         if not strip:
858             return False
859
860         return (strip.type == 'SCENE')
861
862     def draw(self, context):
863         layout = self.layout
864
865         strip = act_strip(context)
866
867         layout.template_ID(strip, "scene")
868
869         scene = strip.scene
870         layout.prop(strip, "use_sequence")
871
872         if not strip.use_sequence:
873             layout.label(text="Camera Override")
874             layout.template_ID(strip, "scene_camera")
875
876             layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil")
877
878         if scene:
879             layout.prop(scene, "audio_volume", text="Audio Volume")
880
881         if not strip.use_sequence:
882             if scene:
883                 # Warning, this is not a good convention to follow.
884                 # Expose here because setting the alpha from the 'Render' menu is very inconvenient.
885                 layout.label("Preview")
886                 layout.prop(scene.render, "alpha_mode")
887
888         if scene:
889             sta = scene.frame_start
890             end = scene.frame_end
891             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
892
893
894 class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
895     bl_label = "Mask"
896     bl_category = "Strip"
897
898     @classmethod
899     def poll(cls, context):
900         if not cls.has_sequencer(context):
901             return False
902
903         strip = act_strip(context)
904         if not strip:
905             return False
906
907         return (strip.type == 'MASK')
908
909     def draw(self, context):
910         layout = self.layout
911
912         strip = act_strip(context)
913
914         layout.template_ID(strip, "mask")
915
916         mask = strip.mask
917
918         if mask:
919             sta = mask.frame_start
920             end = mask.frame_end
921             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
922
923
924 class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
925     bl_label = "Filter"
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 in {'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK',
938                               'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
939                               'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
940                               'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
941                               'MULTICAM', 'SPEED', 'ADJUSTMENT'}
942
943     def draw(self, context):
944         layout = self.layout
945
946         strip = act_strip(context)
947
948         col = layout.column()
949         col.label(text="Video:")
950         col.prop(strip, "strobe")
951
952         if strip.type == 'MOVIECLIP':
953             col = layout.column()
954             col.label(text="Tracker:")
955             col.prop(strip, "stabilize2d")
956
957             col = layout.column()
958             col.label(text="Distortion:")
959             col.prop(strip, "undistort")
960
961         split = layout.split(percentage=0.65)
962
963         col = split.column()
964         col.prop(strip, "use_reverse_frames", text="Backwards")
965         col.prop(strip, "use_deinterlace")
966
967         col = split.column()
968         col.label(text="Flip:")
969         col.prop(strip, "use_flip_x", text="X")
970         col.prop(strip, "use_flip_y", text="Y")
971
972         col = layout.column()
973         col.label(text="Colors:")
974         col.prop(strip, "color_saturation", text="Saturation")
975         col.prop(strip, "color_multiply", text="Multiply")
976         col.prop(strip, "use_float")
977
978
979 class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
980     bl_label = "Proxy/Timecode"
981     bl_category = "Strip"
982
983     @classmethod
984     def poll(cls, context):
985         if not cls.has_sequencer(context):
986             return False
987
988         strip = act_strip(context)
989         if not strip:
990             return False
991
992         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'META', 'MULTICAM'}
993
994     def draw_header(self, context):
995         strip = act_strip(context)
996
997         self.layout.prop(strip, "use_proxy", text="")
998
999     def draw(self, context):
1000         layout = self.layout
1001
1002         sequencer = context.scene.sequence_editor
1003
1004         strip = act_strip(context)
1005
1006         if strip.proxy:
1007             proxy = strip.proxy
1008
1009             flow = layout.column_flow()
1010             flow.prop(sequencer, "proxy_storage")
1011             if sequencer.proxy_storage == 'PROJECT':
1012                 flow.prop(sequencer, "proxy_dir")
1013             else:
1014                 flow.prop(proxy, "use_proxy_custom_directory")
1015                 flow.prop(proxy, "use_proxy_custom_file")
1016
1017                 if proxy.use_proxy_custom_directory and not proxy.use_proxy_custom_file:
1018                     flow.prop(proxy, "directory")
1019                 if proxy.use_proxy_custom_file:
1020                     flow.prop(proxy, "filepath")
1021
1022             row = layout.row(align=True)
1023             row.prop(strip.proxy, "build_25", toggle=True)
1024             row.prop(strip.proxy, "build_50", toggle=True)
1025             row.prop(strip.proxy, "build_75", toggle=True)
1026             row.prop(strip.proxy, "build_100", toggle=True)
1027
1028             layout.prop(proxy, "use_overwrite")
1029
1030             col = layout.column()
1031             col.label(text="Build JPEG quality")
1032             col.prop(proxy, "quality")
1033
1034             if strip.type == 'MOVIE':
1035                 col = layout.column()
1036                 col.label(text="Use timecode index:")
1037
1038                 col.prop(proxy, "timecode")
1039
1040         col = layout.column()
1041         col.operator("sequencer.enable_proxies")
1042         col.operator("sequencer.rebuild_proxy")
1043
1044
1045 class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
1046     bl_label = "Scene Preview/Render"
1047     bl_space_type = 'SEQUENCE_EDITOR'
1048     bl_region_type = 'UI'
1049
1050     def draw(self, context):
1051         layout = self.layout
1052
1053         render = context.scene.render
1054
1055         col = layout.column()
1056         col.prop(render, "use_sequencer_gl_preview", text="OpenGL Preview")
1057         col = layout.column()
1058         #col.active = render.use_sequencer_gl_preview
1059         col.prop(render, "sequencer_gl_preview", text="")
1060
1061         row = col.row()
1062         row.active = render.sequencer_gl_preview == 'SOLID'
1063         row.prop(render, "use_sequencer_gl_textured_solid")
1064
1065
1066 class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
1067     bl_label = "View Settings"
1068
1069     def draw(self, context):
1070         layout = self.layout
1071
1072         st = context.space_data
1073
1074         col = layout.column()
1075         if st.display_mode == 'IMAGE':
1076             col.prop(st, "draw_overexposed")
1077             col.separator()
1078
1079         elif st.display_mode == 'WAVEFORM':
1080             col.prop(st, "show_separate_color")
1081
1082         col = layout.column()
1083         col.separator()
1084         col.prop(st, "proxy_render_size")
1085
1086
1087 class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel):
1088     bl_label = "Safe Areas"
1089     bl_options = {'DEFAULT_CLOSED'}
1090
1091     @classmethod
1092     def poll(cls, context):
1093         st = context.space_data
1094         is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}
1095         return is_preview and (st.display_mode == 'IMAGE')
1096
1097     def draw_header(self, context):
1098         st = context.space_data
1099
1100         self.layout.prop(st, "show_safe_areas", text="")
1101
1102     def draw(self, context):
1103         from bl_ui.properties_data_camera import draw_display_safe_settings
1104
1105         layout = self.layout
1106         st = context.space_data
1107         safe_data = context.scene.safe_areas
1108
1109         draw_display_safe_settings(layout, safe_data, st)
1110
1111
1112 class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
1113     bl_label = "Modifiers"
1114     bl_category = "Modifiers"
1115
1116     def draw(self, context):
1117         layout = self.layout
1118
1119         strip = act_strip(context)
1120         sequencer = context.scene.sequence_editor
1121
1122         layout.prop(strip, "use_linear_modifiers")
1123
1124         layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
1125         layout.operator("sequencer.strip_modifier_copy")
1126
1127         for mod in strip.modifiers:
1128             box = layout.box()
1129
1130             row = box.row()
1131             row.prop(mod, "show_expanded", text="", emboss=False)
1132             row.prop(mod, "name", text="")
1133
1134             row.prop(mod, "mute", text="")
1135
1136             sub = row.row(align=True)
1137             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_UP')
1138             props.name = mod.name
1139             props.direction = 'UP'
1140             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_DOWN')
1141             props.name = mod.name
1142             props.direction = 'DOWN'
1143
1144             row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name
1145
1146             if mod.show_expanded:
1147                 row = box.row()
1148                 row.prop(mod, "input_mask_type", expand=True)
1149
1150                 if mod.input_mask_type == 'STRIP':
1151                     sequences_object = sequencer
1152                     if sequencer.meta_stack:
1153                         sequences_object = sequencer.meta_stack[-1]
1154                     box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
1155                 else:
1156                     box.prop(mod, "input_mask_id")
1157                     row = box.row()
1158                     row.prop(mod, "mask_time", expand=True)
1159
1160                 if mod.type == 'COLOR_BALANCE':
1161                     box.prop(mod, "color_multiply")
1162                     draw_color_balance(box, mod.color_balance)
1163                 elif mod.type == 'CURVES':
1164                     box.template_curve_mapping(mod, "curve_mapping", type='COLOR')
1165                 elif mod.type == 'HUE_CORRECT':
1166                     box.template_curve_mapping(mod, "curve_mapping", type='HUE')
1167                 elif mod.type == 'BRIGHT_CONTRAST':
1168                     col = box.column()
1169                     col.prop(mod, "bright")
1170                     col.prop(mod, "contrast")
1171                 elif mod.type == 'WHITE_BALANCE':
1172                     col = box.column()
1173                     col.prop(mod, "white_value")
1174                 elif mod.type == 'TONEMAP':
1175                     col = box.column()
1176                     col.prop(mod, "tonemap_type")
1177                     if mod.tonemap_type == 'RD_PHOTORECEPTOR':
1178                         col.prop(mod, "intensity")
1179                         col.prop(mod, "contrast")
1180                         col.prop(mod, "adaptation")
1181                         col.prop(mod, "correction")
1182                     elif mod.tonemap_type == 'RH_SIMPLE':
1183                         col.prop(mod, "key")
1184                         col.prop(mod, "offset")
1185                         col.prop(mod, "gamma")
1186
1187
1188 class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Output, Panel):
1189     bl_space_type = 'SEQUENCE_EDITOR'
1190     bl_region_type = 'UI'
1191
1192     # NOTE: this is just a wrapper around the generic GP Panel
1193     # But, it should only show up when there are images in the preview region
1194
1195
1196 class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel):
1197     bl_space_type = 'SEQUENCE_EDITOR'
1198     bl_region_type = 'UI'
1199
1200     # NOTE: this is just a wrapper around the generic GP Panel
1201     # But, it should only show up when there are images in the preview region
1202
1203
1204 class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
1205     bl_space_type = 'SEQUENCE_EDITOR'
1206     bl_region_type = 'UI'
1207
1208     # NOTE: this is just a wrapper around the generic GP tools panel
1209     # It contains access to some essential tools usually found only in
1210     # toolbar, which doesn't exist here...
1211
1212
1213 class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
1214     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
1215     _context_path = "scene.sequence_editor.active_strip"
1216     _property_type = (bpy.types.Sequence,)
1217     bl_category = "Strip"
1218
1219
1220 if __name__ == "__main__":  # only for live edit.
1221     bpy.utils.register_module(__name__)