Fix [#37409] Missing Buttons in Edit Strip Sub-Menu for Sound Strips in the VSE
[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 bpy.app.translations import pgettext_iface as iface_
23
24
25 def act_strip(context):
26     try:
27         return context.scene.sequence_editor.active_strip
28     except AttributeError:
29         return None
30
31
32 def draw_color_balance(layout, color_balance):
33     col = layout.column()
34     col.label(text="Lift:")
35     col.template_color_picker(color_balance, "lift", value_slider=True, cubic=True)
36     row = col.row()
37     row.prop(color_balance, "lift", text="")
38     row.prop(color_balance, "invert_lift", text="Inverse")
39
40     col = layout.column()
41     col.label(text="Gamma:")
42     col.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True)
43     row = col.row()
44     row.prop(color_balance, "gamma", text="")
45     row.prop(color_balance, "invert_gamma", text="Inverse")
46
47     col = layout.column()
48     col.label(text="Gain:")
49     col.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)
50     row = col.row()
51     row.prop(color_balance, "gain", text="")
52     row.prop(color_balance, "invert_gain", text="Inverse")
53
54
55 class SEQUENCER_HT_header(Header):
56     bl_space_type = 'SEQUENCE_EDITOR'
57
58     def draw(self, context):
59         layout = self.layout
60
61         st = context.space_data
62
63         row = layout.row(align=True)
64         row.template_header()
65
66         if context.area.show_menus:
67             row.menu("SEQUENCER_MT_view")
68
69             if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
70                 row.menu("SEQUENCER_MT_select")
71                 row.menu("SEQUENCER_MT_marker")
72                 row.menu("SEQUENCER_MT_add")
73                 row.menu("SEQUENCER_MT_strip")
74
75         layout.prop(st, "view_type", expand=True, text="")
76
77         if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
78             layout.prop(st, "display_mode", expand=True, text="")
79
80         if st.view_type == 'SEQUENCER':
81             row = layout.row(align=True)
82             row.operator("sequencer.copy", text="", icon='COPYDOWN')
83             row.operator("sequencer.paste", text="", icon='PASTEDOWN')
84
85             layout.separator()
86             layout.operator("sequencer.refresh_all")
87         else:
88             if st.view_type == 'SEQUENCER_PREVIEW':
89                 layout.separator()
90                 layout.operator("sequencer.refresh_all")
91
92             layout.prop(st, "preview_channels", expand=True, text="")
93             layout.prop(st, "display_channel", text="Channel")
94
95             ed = context.scene.sequence_editor
96             if ed:
97                 row = layout.row(align=True)
98                 row.prop(ed, "show_overlay", text="", icon='GHOST_ENABLED')
99                 if ed.show_overlay:
100                     row.prop(ed, "overlay_frame", text="")
101                     row.prop(ed, "use_overlay_lock", text="", icon='LOCKED')
102
103                     row = layout.row()
104                     row.prop(st, "overlay_type", text="")
105
106         row = layout.row(align=True)
107         row.operator("render.opengl", text="", icon='RENDER_STILL').sequencer = True
108         props = row.operator("render.opengl", text="", icon='RENDER_ANIMATION')
109         props.animation = True
110         props.sequencer = True
111
112         layout.template_running_jobs()
113
114
115 class SEQUENCER_MT_view_toggle(Menu):
116     bl_label = "View Type"
117
118     def draw(self, context):
119         layout = self.layout
120
121         layout.operator("sequencer.view_toggle").type = 'SEQUENCER'
122         layout.operator("sequencer.view_toggle").type = 'PREVIEW'
123         layout.operator("sequencer.view_toggle").type = 'SEQUENCER_PREVIEW'
124
125
126 class SEQUENCER_MT_view(Menu):
127     bl_label = "View"
128
129     def draw(self, context):
130         layout = self.layout
131
132         st = context.space_data
133
134         if st.view_type in {'PREVIEW'}:
135             # Specifying the REGION_PREVIEW context is needed in preview-only
136             # mode, else the lookup for the shortcut will fail in
137             # wm_keymap_item_find_props() (see #32595).
138             layout.operator_context = 'INVOKE_REGION_PREVIEW'
139         layout.operator("sequencer.properties", icon='MENU_PANEL')
140         layout.operator_context = 'INVOKE_DEFAULT'
141
142         layout.separator()
143
144         if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
145             layout.operator("sequencer.view_all", text="View all Sequences")
146             layout.operator("sequencer.view_selected")
147         if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
148             layout.operator_context = 'INVOKE_REGION_PREVIEW'
149             layout.operator("sequencer.view_all_preview", text="Fit preview in window")
150             layout.operator("sequencer.view_zoom_ratio", text="Show preview 1:1").ratio = 1.0
151             layout.operator_context = 'INVOKE_DEFAULT'
152
153             # # XXX, invokes in the header view
154             # layout.operator("sequencer.view_ghost_border", text="Overlay Border")
155
156         if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
157             layout.prop(st, "show_seconds")
158             layout.prop(st, "show_frame_indicator")
159
160         if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
161             if st.display_mode == 'IMAGE':
162                 layout.prop(st, "show_safe_margin")
163             elif st.display_mode == 'WAVEFORM':
164                 layout.prop(st, "show_separate_color")
165
166         layout.separator()
167
168         if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
169             layout.prop(st, "use_marker_sync")
170             layout.separator()
171
172         layout.operator("screen.area_dupli")
173         layout.operator("screen.screen_full_area")
174
175
176 class SEQUENCER_MT_select(Menu):
177     bl_label = "Select"
178
179     def draw(self, context):
180         layout = self.layout
181
182         layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT'
183         layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT'
184         layout.separator()
185         layout.operator("sequencer.select_handles", text="Surrounding Handles").side = 'BOTH'
186         layout.operator("sequencer.select_handles", text="Left Handle").side = 'LEFT'
187         layout.operator("sequencer.select_handles", text="Right Handle").side = 'RIGHT'
188         layout.separator()
189         layout.operator_menu_enum("sequencer.select_grouped", "type", text="Grouped")
190         layout.operator("sequencer.select_linked")
191         layout.operator("sequencer.select_all").action = 'TOGGLE'
192         layout.operator("sequencer.select_all", text="Inverse").action = 'INVERT'
193
194
195 class SEQUENCER_MT_marker(Menu):
196     bl_label = "Marker"
197
198     def draw(self, context):
199         layout = self.layout
200
201         from bl_ui.space_time import marker_menu_generic
202         marker_menu_generic(layout)
203
204
205 class SEQUENCER_MT_change(Menu):
206     bl_label = "Change"
207
208     def draw(self, context):
209         layout = self.layout
210
211         layout.operator_context = 'INVOKE_REGION_WIN'
212
213         layout.operator_menu_enum("sequencer.change_effect_input", "swap")
214         layout.operator_menu_enum("sequencer.change_effect_type", "type")
215         layout.operator("sequencer.change_path", text="Path/Files")
216
217
218 class SEQUENCER_MT_add(Menu):
219     bl_label = "Add"
220
221     def draw(self, context):
222         layout = self.layout
223
224         layout.operator_context = 'INVOKE_REGION_WIN'
225
226         if len(bpy.data.scenes) > 10:
227             layout.operator_context = 'INVOKE_DEFAULT'
228             layout.operator("sequencer.scene_strip_add", text="Scene...")
229         else:
230             layout.operator_menu_enum("sequencer.scene_strip_add", "scene", text="Scene...")
231
232         if len(bpy.data.movieclips) > 10:
233             layout.operator_context = 'INVOKE_DEFAULT'
234             layout.operator("sequencer.movieclip_strip_add", text="Clips...")
235         else:
236             layout.operator_menu_enum("sequencer.movieclip_strip_add", "clip", text="Clip...")
237
238         if len(bpy.data.masks) > 10:
239             layout.operator_context = 'INVOKE_DEFAULT'
240             layout.operator("sequencer.mask_strip_add", text="Masks...")
241         else:
242             layout.operator_menu_enum("sequencer.mask_strip_add", "mask", text="Mask...")
243
244         layout.operator("sequencer.movie_strip_add", text="Movie")
245         layout.operator("sequencer.image_strip_add", text="Image")
246         layout.operator("sequencer.sound_strip_add", text="Sound")
247
248         layout.menu("SEQUENCER_MT_add_effect")
249
250
251 class SEQUENCER_MT_add_effect(Menu):
252     bl_label = "Effect Strip..."
253
254     def draw(self, context):
255         layout = self.layout
256
257         layout.operator_context = 'INVOKE_REGION_WIN'
258
259         layout.operator("sequencer.effect_strip_add", text="Add").type = 'ADD'
260         layout.operator("sequencer.effect_strip_add", text="Subtract").type = 'SUBTRACT'
261         layout.operator("sequencer.effect_strip_add", text="Alpha Over").type = 'ALPHA_OVER'
262         layout.operator("sequencer.effect_strip_add", text="Alpha Under").type = 'ALPHA_UNDER'
263         layout.operator("sequencer.effect_strip_add", text="Cross").type = 'CROSS'
264         layout.operator("sequencer.effect_strip_add", text="Gamma Cross").type = 'GAMMA_CROSS'
265         layout.operator("sequencer.effect_strip_add", text="Multiply").type = 'MULTIPLY'
266         layout.operator("sequencer.effect_strip_add", text="Over Drop").type = 'OVER_DROP'
267         layout.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE'
268         layout.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW'
269         layout.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM'
270         layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR'
271         layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'
272         layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM'
273         layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT'
274
275
276 class SEQUENCER_MT_strip(Menu):
277     bl_label = "Strip"
278
279     def draw(self, context):
280         layout = self.layout
281
282         layout.operator_context = 'INVOKE_REGION_WIN'
283
284         layout.operator("transform.transform", text="Grab/Move").mode = 'TRANSLATION'
285         layout.operator("transform.transform", text="Grab/Extend from frame").mode = 'TIME_EXTEND'
286         layout.operator("sequencer.gap_remove")
287         layout.operator("sequencer.gap_insert")
288
289         #  uiItemO(layout, NULL, 0, "sequencer.strip_snap"); // TODO - add this operator
290         layout.separator()
291
292         layout.operator("sequencer.cut", text="Cut (hard) at frame").type = 'HARD'
293         layout.operator("sequencer.cut", text="Cut (soft) at frame").type = 'SOFT'
294         layout.operator("sequencer.images_separate")
295         layout.operator("sequencer.offset_clear")
296         layout.operator("sequencer.deinterlace_selected_movies")
297         layout.operator("sequencer.rebuild_proxy")
298         layout.separator()
299
300         layout.operator("sequencer.duplicate_move")
301         layout.operator("sequencer.delete")
302
303         strip = act_strip(context)
304
305         if strip:
306             stype = strip.type
307
308             # XXX note strip.type is never equal to 'EFFECT', look at seq_type_items within rna_sequencer.c
309             if stype == 'EFFECT':
310                 pass
311                 # layout.separator()
312                 # layout.operator("sequencer.effect_change")
313                 # layout.operator("sequencer.effect_reassign_inputs")
314             elif stype == 'IMAGE':
315                 layout.separator()
316                 # layout.operator("sequencer.image_change")
317                 layout.operator("sequencer.rendersize")
318             elif stype == 'SCENE':
319                 pass
320                 # layout.separator()
321                 # layout.operator("sequencer.scene_change", text="Change Scene")
322             elif stype == 'MOVIE':
323                 layout.separator()
324                 # layout.operator("sequencer.movie_change")
325                 layout.operator("sequencer.rendersize")
326             elif stype == 'SOUND':
327                 layout.separator()
328                 layout.operator("sequencer.crossfade_sounds")
329
330         layout.separator()
331
332         layout.operator("sequencer.meta_make")
333         layout.operator("sequencer.meta_separate")
334
335         #if (ed && (ed->metastack.first || (ed->act_seq && ed->act_seq->type == SEQ_META))) {
336         #       uiItemS(layout);
337         #       uiItemO(layout, NULL, 0, "sequencer.meta_toggle");
338         #}
339
340         layout.separator()
341         layout.operator("sequencer.reload", text="Reload Strips").adjust_length = False
342         layout.operator("sequencer.reload", text="Reload Strips and Adjust Length").adjust_length = True
343         layout.operator("sequencer.reassign_inputs")
344         layout.operator("sequencer.swap_inputs")
345
346         layout.separator()
347         layout.operator("sequencer.lock")
348         layout.operator("sequencer.unlock")
349         layout.operator("sequencer.mute").unselected = False
350         layout.operator("sequencer.unmute")
351
352         layout.operator("sequencer.mute", text="Mute Deselected Strips").unselected = True
353
354         layout.operator("sequencer.snap")
355
356         layout.operator_menu_enum("sequencer.swap", "side")
357
358         layout.separator()
359
360         layout.operator("sequencer.swap_data")
361         layout.menu("SEQUENCER_MT_change")
362
363
364 class SequencerButtonsPanel():
365     bl_space_type = 'SEQUENCE_EDITOR'
366     bl_region_type = 'UI'
367
368     @staticmethod
369     def has_sequencer(context):
370         return (context.space_data.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'})
371
372     @classmethod
373     def poll(cls, context):
374         return cls.has_sequencer(context) and (act_strip(context) is not None)
375
376
377 class SequencerButtonsPanel_Output():
378     bl_space_type = 'SEQUENCE_EDITOR'
379     bl_region_type = 'UI'
380
381     @staticmethod
382     def has_preview(context):
383         return (context.space_data.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'})
384
385     @classmethod
386     def poll(cls, context):
387         return cls.has_preview(context)
388
389
390 class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
391     bl_label = "Edit Strip"
392
393     def draw(self, context):
394         layout = self.layout
395
396         scene = context.scene
397         frame_current = scene.frame_current
398         strip = act_strip(context)
399
400         split = layout.split(percentage=0.3)
401         split.label(text="Name:")
402         split.prop(strip, "name", text="")
403
404         split = layout.split(percentage=0.3)
405         split.label(text="Type:")
406         split.prop(strip, "type", text="")
407
408         if strip.type not in {'SOUND'}:
409             split = layout.split(percentage=0.3)
410             split.label(text="Blend:")
411             split.prop(strip, "blend_type", text="")
412
413             row = layout.row(align=True)
414             sub = row.row(align=True)
415             sub.active = (not strip.mute)
416             sub.prop(strip, "blend_alpha", text="Opacity", slider=True)
417             row.prop(strip, "mute", toggle=True, icon='RESTRICT_VIEW_ON' if strip.mute else 'RESTRICT_VIEW_OFF', text="")
418             row.prop(strip, "lock", toggle=True, icon='LOCKED' if strip.lock else 'UNLOCKED', text="")
419         else:
420             row = layout.row(align=True)
421             row.prop(strip, "mute", toggle=True, icon='RESTRICT_VIEW_ON' if strip.mute else 'RESTRICT_VIEW_OFF')
422             row.prop(strip, "lock", toggle=True, icon='LOCKED' if strip.lock else 'UNLOCKED')
423
424         col = layout.column()
425         sub = col.column()
426         sub.enabled = not strip.lock
427         sub.prop(strip, "channel")
428         sub.prop(strip, "frame_start")
429         sub.prop(strip, "frame_final_duration")
430
431         col = layout.column(align=True)
432         row = col.row(align=True)
433         row.label(text=iface_("Final Length: %s") % bpy.utils.smpte_from_frame(strip.frame_final_duration),
434                   translate=False)
435         row = col.row(align=True)
436         row.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_duration)
437         row.label(text=iface_("Playhead: %d") % (frame_current - strip.frame_start), translate=False)
438
439         col.label(text=iface_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end),
440                   translate=False)
441         col.label(text=iface_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end), translate=False)
442
443         elem = False
444
445         if strip.type == 'IMAGE':
446             elem = strip.strip_elem_from_frame(frame_current)
447         elif strip.type == 'MOVIE':
448             elem = strip.elements[0]
449
450         if elem and elem.orig_width > 0 and elem.orig_height > 0:
451             col.label(text=iface_("Original Dimension: %dx%d") % (elem.orig_width, elem.orig_height), translate=False)
452         else:
453             col.label(text="Original Dimension: None")
454
455
456 class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
457     bl_label = "Effect Strip"
458
459     @classmethod
460     def poll(cls, context):
461         if not cls.has_sequencer(context):
462             return False
463
464         strip = act_strip(context)
465         if not strip:
466             return False
467
468         return strip.type in {'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
469                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
470                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
471                               'MULTICAM'}
472
473     def draw(self, context):
474         layout = self.layout
475
476         sequencer = context.scene.sequence_editor
477         strip = act_strip(context)
478
479         if strip.input_count > 0:
480             col = layout.column()
481             col.prop(strip, "input_1")
482             if strip.input_count > 1:
483                 col.prop(strip, "input_2")
484
485         if strip.type == 'COLOR':
486             layout.prop(strip, "color")
487
488         elif strip.type == 'WIPE':
489             col = layout.column()
490             col.prop(strip, "transition_type")
491             col.label(text="Direction:")
492             col.row().prop(strip, "direction", expand=True)
493
494             col = layout.column()
495             col.prop(strip, "blur_width", slider=True)
496             if strip.transition_type in {'SINGLE', 'DOUBLE'}:
497                 col.prop(strip, "angle")
498
499         elif strip.type == 'GLOW':
500             flow = layout.column_flow()
501             flow.prop(strip, "threshold", slider=True)
502             flow.prop(strip, "clamp", slider=True)
503             flow.prop(strip, "boost_factor")
504             flow.prop(strip, "blur_radius")
505
506             row = layout.row()
507             row.prop(strip, "quality", slider=True)
508             row.prop(strip, "use_only_boost")
509
510         elif strip.type == 'SPEED':
511             layout.prop(strip, "use_default_fade", "Stretch to input strip length")
512             if not strip.use_default_fade:
513                 layout.prop(strip, "use_as_speed")
514                 if strip.use_as_speed:
515                     layout.prop(strip, "speed_factor")
516                 else:
517                     layout.prop(strip, "speed_factor", text="Frame number")
518                     layout.prop(strip, "scale_to_length")
519
520         elif strip.type == 'TRANSFORM':
521             layout = self.layout
522             col = layout.column()
523
524             col.prop(strip, "interpolation")
525             col.prop(strip, "translation_unit")
526             col = layout.column(align=True)
527             col.label(text="Position:")
528             col.prop(strip, "translate_start_x", text="X")
529             col.prop(strip, "translate_start_y", text="Y")
530
531             layout.separator()
532
533             col = layout.column(align=True)
534             col.prop(strip, "use_uniform_scale")
535             if strip.use_uniform_scale:
536                 col = layout.column(align=True)
537                 col.prop(strip, "scale_start_x", text="Scale")
538             else:
539                 col = layout.column(align=True)
540                 col.label(text="Scale:")
541                 col.prop(strip, "scale_start_x", text="X")
542                 col.prop(strip, "scale_start_y", text="Y")
543
544             layout.separator()
545
546             col = layout.column(align=True)
547             col.label(text="Rotation:")
548             col.prop(strip, "rotation_start", text="Rotation")
549
550         elif strip.type == 'MULTICAM':
551             layout.prop(strip, "multicam_source")
552
553             row = layout.row(align=True)
554             sub = row.row(align=True)
555             sub.scale_x = 2.0
556
557             sub.operator("screen.animation_play", text="", icon='PAUSE' if context.screen.is_animation_playing else 'PLAY')
558
559             row.label("Cut To")
560             for i in range(1, strip.channel):
561                 row.operator("sequencer.cut_multicam", text="%d" % i).camera = i
562
563         col = layout.column(align=True)
564         if strip.type == 'SPEED':
565             col.prop(strip, "multiply_speed")
566         elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE'}:
567             col.prop(strip, "use_default_fade", "Default fade")
568             if not strip.use_default_fade:
569                 col.prop(strip, "effect_fader", text="Effect fader")
570
571
572 class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
573     bl_label = "Strip Input"
574
575     @classmethod
576     def poll(cls, context):
577         if not cls.has_sequencer(context):
578             return False
579
580         strip = act_strip(context)
581         if not strip:
582             return False
583
584         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'META',
585                               'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
586                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
587                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
588                               'MULTICAM', 'SPEED', 'ADJUSTMENT'}
589
590     def draw(self, context):
591         layout = self.layout
592
593         strip = act_strip(context)
594
595         seq_type = strip.type
596
597         # draw a filename if we have one
598         if seq_type == 'IMAGE':
599             split = layout.split(percentage=0.2)
600             split.label(text="Path:")
601             split.prop(strip, "directory", text="")
602
603             # Current element for the filename
604
605             elem = strip.strip_elem_from_frame(context.scene.frame_current)
606             if elem:
607                 split = layout.split(percentage=0.2)
608                 split.label(text="File:")
609                 split.prop(elem, "filename", text="")  # strip.elements[0] could be a fallback
610
611             layout.prop(strip.colorspace_settings, "name")
612             layout.prop(strip, "alpha_mode")
613
614             layout.operator("sequencer.change_path")
615
616         elif seq_type == 'MOVIE':
617             split = layout.split(percentage=0.2)
618             split.label(text="Path:")
619             split.prop(strip, "filepath", text="")
620
621             layout.prop(strip.colorspace_settings, "name")
622
623             layout.prop(strip, "mpeg_preseek")
624             layout.prop(strip, "stream_index")
625
626         layout.prop(strip, "use_translation", text="Image Offset")
627         if strip.use_translation:
628             col = layout.column(align=True)
629             col.prop(strip.transform, "offset_x", text="X")
630             col.prop(strip.transform, "offset_y", text="Y")
631
632         layout.prop(strip, "use_crop", text="Image Crop")
633         if strip.use_crop:
634             col = layout.column(align=True)
635             col.prop(strip.crop, "max_y")
636             col.prop(strip.crop, "min_x")
637             col.prop(strip.crop, "min_y")
638             col.prop(strip.crop, "max_x")
639
640         if not isinstance(strip, bpy.types.EffectSequence):
641             col = layout.column(align=True)
642             col.label(text="Trim Duration (hard):")
643             col.prop(strip, "animation_offset_start", text="Start")
644             col.prop(strip, "animation_offset_end", text="End")
645
646         col = layout.column(align=True)
647         col.label(text="Trim Duration (soft):")
648         col.prop(strip, "frame_offset_start", text="Start")
649         col.prop(strip, "frame_offset_end", text="End")
650
651
652 class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
653     bl_label = "Sound"
654
655     @classmethod
656     def poll(cls, context):
657         if not cls.has_sequencer(context):
658             return False
659
660         strip = act_strip(context)
661         if not strip:
662             return False
663
664         return (strip.type == 'SOUND')
665
666     def draw(self, context):
667         layout = self.layout
668
669         strip = act_strip(context)
670         sound = strip.sound
671
672         layout.template_ID(strip, "sound", open="sound.open")
673
674         layout.separator()
675         layout.prop(strip, "filepath", text="")
676
677         if sound is not None:
678             row = layout.row()
679             if sound.packed_file:
680                 row.operator("sound.unpack", icon='PACKAGE', text="Unpack")
681             else:
682                 row.operator("sound.pack", icon='UGLYPACKAGE', text="Pack")
683
684             row.prop(sound, "use_memory_cache")
685
686         layout.prop(strip, "show_waveform")
687         layout.prop(strip, "volume")
688         layout.prop(strip, "pitch")
689         layout.prop(strip, "pan")
690
691         col = layout.column(align=True)
692         col.label(text="Trim Duration (hard):")
693         col.prop(strip, "animation_offset_start", text="Start")
694         col.prop(strip, "animation_offset_end", text="End")
695
696         col = layout.column(align=True)
697         col.label(text="Trim Duration (soft):")
698         col.prop(strip, "frame_offset_start", text="Start")
699         col.prop(strip, "frame_offset_end", text="End")
700
701
702 class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
703     bl_label = "Scene"
704
705     @classmethod
706     def poll(cls, context):
707         if not cls.has_sequencer(context):
708             return False
709
710         strip = act_strip(context)
711         if not strip:
712             return False
713
714         return (strip.type == 'SCENE')
715
716     def draw(self, context):
717         layout = self.layout
718
719         strip = act_strip(context)
720
721         layout.template_ID(strip, "scene")
722
723         scene = strip.scene
724
725         layout.label(text="Camera Override")
726         layout.template_ID(strip, "scene_camera")
727
728         if scene:
729             sta = scene.frame_start
730             end = scene.frame_end
731             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
732
733
734 class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
735     bl_label = "Mask"
736
737     @classmethod
738     def poll(cls, context):
739         if not cls.has_sequencer(context):
740             return False
741
742         strip = act_strip(context)
743         if not strip:
744             return False
745
746         return (strip.type == 'MASK')
747
748     def draw(self, context):
749         layout = self.layout
750
751         strip = act_strip(context)
752
753         layout.template_ID(strip, "mask")
754
755         mask = strip.mask
756
757         if mask:
758             sta = mask.frame_start
759             end = mask.frame_end
760             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
761
762
763 class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
764     bl_label = "Filter"
765
766     @classmethod
767     def poll(cls, context):
768         if not cls.has_sequencer(context):
769             return False
770
771         strip = act_strip(context)
772         if not strip:
773             return False
774
775         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK',
776                               'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
777                               'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
778                               'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
779                               'MULTICAM', 'SPEED', 'ADJUSTMENT'}
780
781     def draw(self, context):
782         layout = self.layout
783
784         strip = act_strip(context)
785
786         col = layout.column()
787         col.label(text="Video:")
788         col.prop(strip, "strobe")
789
790         if strip.type == 'MOVIECLIP':
791             col = layout.column()
792             col.label(text="Tracker:")
793             col.prop(strip, "stabilize2d")
794
795             col = layout.column()
796             col.label(text="Distortion:")
797             col.prop(strip, "undistort")
798
799         split = layout.split(percentage=0.65)
800
801         col = split.column()
802         col.prop(strip, "use_reverse_frames", text="Backwards")
803         col.prop(strip, "use_deinterlace")
804
805         col = split.column()
806         col.label(text="Flip:")
807         col.prop(strip, "use_flip_x", text="X")
808         col.prop(strip, "use_flip_y", text="Y")
809
810         col = layout.column()
811         col.label(text="Colors:")
812         col.prop(strip, "color_saturation", text="Saturation")
813         col.prop(strip, "color_multiply", text="Multiply")
814         col.prop(strip, "use_float")
815
816
817 class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
818     bl_label = "Proxy / Timecode"
819
820     @classmethod
821     def poll(cls, context):
822         if not cls.has_sequencer(context):
823             return False
824
825         strip = act_strip(context)
826         if not strip:
827             return False
828
829         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'META', 'MULTICAM'}
830
831     def draw_header(self, context):
832         strip = act_strip(context)
833
834         self.layout.prop(strip, "use_proxy", text="")
835
836     def draw(self, context):
837         layout = self.layout
838
839         strip = act_strip(context)
840
841         flow = layout.column_flow()
842         flow.prop(strip, "use_proxy_custom_directory")
843         flow.prop(strip, "use_proxy_custom_file")
844         if strip.proxy:
845             if strip.use_proxy_custom_directory and not strip.use_proxy_custom_file:
846                 flow.prop(strip.proxy, "directory")
847             if strip.use_proxy_custom_file:
848                 flow.prop(strip.proxy, "filepath")
849
850             row = layout.row()
851             row.prop(strip.proxy, "build_25")
852             row.prop(strip.proxy, "build_50")
853             row.prop(strip.proxy, "build_75")
854             row.prop(strip.proxy, "build_100")
855
856             col = layout.column()
857             col.label(text="Build JPEG quality")
858             col.prop(strip.proxy, "quality")
859
860             if strip.type == 'MOVIE':
861                 col = layout.column()
862                 col.label(text="Use timecode index:")
863
864                 col.prop(strip.proxy, "timecode")
865
866
867 class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
868     bl_label = "Scene Preview/Render"
869     bl_space_type = 'SEQUENCE_EDITOR'
870     bl_region_type = 'UI'
871
872     def draw(self, context):
873         layout = self.layout
874
875         render = context.scene.render
876
877         col = layout.column()
878         col.prop(render, "use_sequencer_gl_preview", text="Open GL Preview")
879         col = layout.column()
880         #col.active = render.use_sequencer_gl_preview
881         col.prop(render, "sequencer_gl_preview", text="")
882
883         row = col.row()
884         row.active = render.sequencer_gl_preview == 'SOLID'
885         row.prop(render, "use_sequencer_gl_textured_solid")
886
887
888 class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
889     bl_label = "View Settings"
890
891     def draw(self, context):
892         layout = self.layout
893
894         st = context.space_data
895
896         col = layout.column()
897         if st.display_mode == 'IMAGE':
898             col.prop(st, "draw_overexposed")
899             col.prop(st, "show_safe_margin")
900         elif st.display_mode == 'WAVEFORM':
901             col.prop(st, "show_separate_color")
902         col.prop(st, "proxy_render_size")
903
904
905 class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
906     bl_label = "Modifiers"
907
908     def draw(self, context):
909         layout = self.layout
910
911         strip = act_strip(context)
912         sequencer = context.scene.sequence_editor
913
914         layout.prop(strip, "use_linear_modifiers")
915
916         layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
917
918         for mod in strip.modifiers:
919             box = layout.box()
920
921             row = box.row()
922             row.prop(mod, "show_expanded", text="", emboss=False)
923             row.prop(mod, "name", text="")
924
925             row.prop(mod, "mute", text="")
926
927             sub = row.row(align=True)
928             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_UP')
929             props.name = mod.name
930             props.direction = 'UP'
931             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_DOWN')
932             props.name = mod.name
933             props.direction = 'DOWN'
934
935             row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name
936
937             if mod.show_expanded:
938                 row = box.row()
939                 row.prop(mod, "input_mask_type", expand=True)
940
941                 if mod.input_mask_type == 'STRIP':
942                     box.prop_search(mod, "input_mask_strip", sequencer, "sequences", text="Mask")
943                 else:
944                     box.prop(mod, "input_mask_id")
945
946                 if mod.type == 'COLOR_BALANCE':
947                     box.prop(mod, "color_multiply")
948                     draw_color_balance(box, mod.color_balance)
949                 elif mod.type == 'CURVES':
950                     box.template_curve_mapping(mod, "curve_mapping", type='COLOR')
951                 elif mod.type == 'HUE_CORRECT':
952                     box.template_curve_mapping(mod, "curve_mapping", type='HUE')
953                 elif mod.type == 'BRIGHT_CONTRAST':
954                     col = box.column()
955                     col.prop(mod, "bright")
956                     col.prop(mod, "contrast")
957
958
959 if __name__ == "__main__":  # only for live edit.
960     bpy.utils.register_module(__name__)