Fix [#36422] Trimmed audio files (hard cut only) in a metastrip have their trim removed
[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
420         col = layout.column()
421         sub = col.column()
422         sub.enabled = not strip.lock
423         sub.prop(strip, "channel")
424         sub.prop(strip, "frame_start")
425         sub.prop(strip, "frame_final_duration")
426
427         col = layout.column(align=True)
428         row = col.row(align=True)
429         row.label(text=iface_("Final Length: %s") % bpy.utils.smpte_from_frame(strip.frame_final_duration),
430                   translate=False)
431         row = col.row(align=True)
432         row.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_duration)
433         row.label(text=iface_("Playhead: %d") % (frame_current - strip.frame_start), translate=False)
434
435         col.label(text=iface_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end),
436                   translate=False)
437         col.label(text=iface_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end), translate=False)
438
439         elem = False
440
441         if strip.type == 'IMAGE':
442             elem = strip.strip_elem_from_frame(frame_current)
443         elif strip.type == 'MOVIE':
444             elem = strip.elements[0]
445
446         if elem and elem.orig_width > 0 and elem.orig_height > 0:
447             col.label(text=iface_("Original Dimension: %dx%d") % (elem.orig_width, elem.orig_height), translate=False)
448         else:
449             col.label(text="Original Dimension: None")
450
451
452 class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
453     bl_label = "Effect Strip"
454
455     @classmethod
456     def poll(cls, context):
457         if not cls.has_sequencer(context):
458             return False
459
460         strip = act_strip(context)
461         if not strip:
462             return False
463
464         return strip.type in {'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
465                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
466                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
467                               'MULTICAM'}
468
469     def draw(self, context):
470         layout = self.layout
471
472         sequencer = context.scene.sequence_editor
473         strip = act_strip(context)
474
475         if strip.input_count > 0:
476             col = layout.column()
477             col.prop(strip, "input_1")
478             if strip.input_count > 1:
479                 col.prop(strip, "input_2")
480
481         if strip.type == 'COLOR':
482             layout.prop(strip, "color")
483
484         elif strip.type == 'WIPE':
485             col = layout.column()
486             col.prop(strip, "transition_type")
487             col.label(text="Direction:")
488             col.row().prop(strip, "direction", expand=True)
489
490             col = layout.column()
491             col.prop(strip, "blur_width", slider=True)
492             if strip.transition_type in {'SINGLE', 'DOUBLE'}:
493                 col.prop(strip, "angle")
494
495         elif strip.type == 'GLOW':
496             flow = layout.column_flow()
497             flow.prop(strip, "threshold", slider=True)
498             flow.prop(strip, "clamp", slider=True)
499             flow.prop(strip, "boost_factor")
500             flow.prop(strip, "blur_radius")
501
502             row = layout.row()
503             row.prop(strip, "quality", slider=True)
504             row.prop(strip, "use_only_boost")
505
506         elif strip.type == 'SPEED':
507             layout.prop(strip, "use_default_fade", "Stretch to input strip length")
508             if not strip.use_default_fade:
509                 layout.prop(strip, "use_as_speed")
510                 if strip.use_as_speed:
511                     layout.prop(strip, "speed_factor")
512                 else:
513                     layout.prop(strip, "speed_factor", text="Frame number")
514                     layout.prop(strip, "scale_to_length")
515
516         elif strip.type == 'TRANSFORM':
517             layout = self.layout
518             col = layout.column()
519
520             col.prop(strip, "interpolation")
521             col.prop(strip, "translation_unit")
522             col = layout.column(align=True)
523             col.label(text="Position:")
524             col.prop(strip, "translate_start_x", text="X")
525             col.prop(strip, "translate_start_y", text="Y")
526
527             layout.separator()
528
529             col = layout.column(align=True)
530             col.prop(strip, "use_uniform_scale")
531             if strip.use_uniform_scale:
532                 col = layout.column(align=True)
533                 col.prop(strip, "scale_start_x", text="Scale")
534             else:
535                 col = layout.column(align=True)
536                 col.label(text="Scale:")
537                 col.prop(strip, "scale_start_x", text="X")
538                 col.prop(strip, "scale_start_y", text="Y")
539
540             layout.separator()
541
542             col = layout.column(align=True)
543             col.label(text="Rotation:")
544             col.prop(strip, "rotation_start", text="Rotation")
545
546         elif strip.type == 'MULTICAM':
547             layout.prop(strip, "multicam_source")
548
549             row = layout.row(align=True)
550             sub = row.row(align=True)
551             sub.scale_x = 2.0
552
553             sub.operator("screen.animation_play", text="", icon='PAUSE' if context.screen.is_animation_playing else 'PLAY')
554
555             row.label("Cut To")
556             for i in range(1, strip.channel):
557                 row.operator("sequencer.cut_multicam", text="%d" % i).camera = i
558
559         col = layout.column(align=True)
560         if strip.type == 'SPEED':
561             col.prop(strip, "multiply_speed")
562         elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE'}:
563             col.prop(strip, "use_default_fade", "Default fade")
564             if not strip.use_default_fade:
565                 col.prop(strip, "effect_fader", text="Effect fader")
566
567
568 class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
569     bl_label = "Strip Input"
570
571     @classmethod
572     def poll(cls, context):
573         if not cls.has_sequencer(context):
574             return False
575
576         strip = act_strip(context)
577         if not strip:
578             return False
579
580         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'META',
581                               'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
582                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
583                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
584                               'MULTICAM', 'SPEED', 'ADJUSTMENT'}
585
586     def draw(self, context):
587         layout = self.layout
588
589         strip = act_strip(context)
590
591         seq_type = strip.type
592
593         # draw a filename if we have one
594         if seq_type == 'IMAGE':
595             split = layout.split(percentage=0.2)
596             split.label(text="Path:")
597             split.prop(strip, "directory", text="")
598
599             # Current element for the filename
600
601             elem = strip.strip_elem_from_frame(context.scene.frame_current)
602             if elem:
603                 split = layout.split(percentage=0.2)
604                 split.label(text="File:")
605                 split.prop(elem, "filename", text="")  # strip.elements[0] could be a fallback
606
607             layout.prop(strip.colorspace_settings, "name")
608             layout.prop(strip, "alpha_mode")
609
610             layout.operator("sequencer.change_path")
611
612         elif seq_type == 'MOVIE':
613             split = layout.split(percentage=0.2)
614             split.label(text="Path:")
615             split.prop(strip, "filepath", text="")
616
617             layout.prop(strip.colorspace_settings, "name")
618
619             layout.prop(strip, "mpeg_preseek")
620             layout.prop(strip, "stream_index")
621
622         layout.prop(strip, "use_translation", text="Image Offset")
623         if strip.use_translation:
624             col = layout.column(align=True)
625             col.prop(strip.transform, "offset_x", text="X")
626             col.prop(strip.transform, "offset_y", text="Y")
627
628         layout.prop(strip, "use_crop", text="Image Crop")
629         if strip.use_crop:
630             col = layout.column(align=True)
631             col.prop(strip.crop, "max_y")
632             col.prop(strip.crop, "min_x")
633             col.prop(strip.crop, "min_y")
634             col.prop(strip.crop, "max_x")
635
636         if not isinstance(strip, bpy.types.EffectSequence):
637             col = layout.column(align=True)
638             col.label(text="Trim Duration (hard):")
639             col.prop(strip, "animation_offset_start", text="Start")
640             col.prop(strip, "animation_offset_end", text="End")
641
642         col = layout.column(align=True)
643         col.label(text="Trim Duration (soft):")
644         col.prop(strip, "frame_offset_start", text="Start")
645         col.prop(strip, "frame_offset_end", text="End")
646
647
648 class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
649     bl_label = "Sound"
650
651     @classmethod
652     def poll(cls, context):
653         if not cls.has_sequencer(context):
654             return False
655
656         strip = act_strip(context)
657         if not strip:
658             return False
659
660         return (strip.type == 'SOUND')
661
662     def draw(self, context):
663         layout = self.layout
664
665         strip = act_strip(context)
666         sound = strip.sound
667
668         layout.template_ID(strip, "sound", open="sound.open")
669
670         layout.separator()
671         layout.prop(strip, "filepath", text="")
672
673         if sound is not None:
674             row = layout.row()
675             if sound.packed_file:
676                 row.operator("sound.unpack", icon='PACKAGE', text="Unpack")
677             else:
678                 row.operator("sound.pack", icon='UGLYPACKAGE', text="Pack")
679
680             row.prop(sound, "use_memory_cache")
681
682         layout.prop(strip, "show_waveform")
683         layout.prop(strip, "volume")
684         layout.prop(strip, "pitch")
685         layout.prop(strip, "pan")
686
687         col = layout.column(align=True)
688         col.label(text="Trim Duration (hard):")
689         col.prop(strip, "animation_offset_start", text="Start")
690         col.prop(strip, "animation_offset_end", text="End")
691
692         col = layout.column(align=True)
693         col.label(text="Trim Duration (soft):")
694         col.prop(strip, "frame_offset_start", text="Start")
695         col.prop(strip, "frame_offset_end", text="End")
696
697
698 class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
699     bl_label = "Scene"
700
701     @classmethod
702     def poll(cls, context):
703         if not cls.has_sequencer(context):
704             return False
705
706         strip = act_strip(context)
707         if not strip:
708             return False
709
710         return (strip.type == 'SCENE')
711
712     def draw(self, context):
713         layout = self.layout
714
715         strip = act_strip(context)
716
717         layout.template_ID(strip, "scene")
718
719         scene = strip.scene
720
721         layout.label(text="Camera Override")
722         layout.template_ID(strip, "scene_camera")
723
724         if scene:
725             sta = scene.frame_start
726             end = scene.frame_end
727             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
728
729
730 class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
731     bl_label = "Mask"
732
733     @classmethod
734     def poll(cls, context):
735         if not cls.has_sequencer(context):
736             return False
737
738         strip = act_strip(context)
739         if not strip:
740             return False
741
742         return (strip.type == 'MASK')
743
744     def draw(self, context):
745         layout = self.layout
746
747         strip = act_strip(context)
748
749         layout.template_ID(strip, "mask")
750
751         mask = strip.mask
752
753         if mask:
754             sta = mask.frame_start
755             end = mask.frame_end
756             layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
757
758
759 class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
760     bl_label = "Filter"
761
762     @classmethod
763     def poll(cls, context):
764         if not cls.has_sequencer(context):
765             return False
766
767         strip = act_strip(context)
768         if not strip:
769             return False
770
771         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK',
772                               'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
773                               'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
774                               'OVER_DROP', 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
775                               'MULTICAM', 'SPEED', 'ADJUSTMENT'}
776
777     def draw(self, context):
778         layout = self.layout
779
780         strip = act_strip(context)
781
782         col = layout.column()
783         col.label(text="Video:")
784         col.prop(strip, "strobe")
785
786         if strip.type == 'MOVIECLIP':
787             col = layout.column()
788             col.label(text="Tracker:")
789             col.prop(strip, "stabilize2d")
790
791             col = layout.column()
792             col.label(text="Distortion:")
793             col.prop(strip, "undistort")
794
795         split = layout.split(percentage=0.65)
796
797         col = split.column()
798         col.prop(strip, "use_reverse_frames", text="Backwards")
799         col.prop(strip, "use_deinterlace")
800
801         col = split.column()
802         col.label(text="Flip:")
803         col.prop(strip, "use_flip_x", text="X")
804         col.prop(strip, "use_flip_y", text="Y")
805
806         col = layout.column()
807         col.label(text="Colors:")
808         col.prop(strip, "color_saturation", text="Saturation")
809         col.prop(strip, "color_multiply", text="Multiply")
810         col.prop(strip, "use_float")
811
812
813 class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
814     bl_label = "Proxy / Timecode"
815
816     @classmethod
817     def poll(cls, context):
818         if not cls.has_sequencer(context):
819             return False
820
821         strip = act_strip(context)
822         if not strip:
823             return False
824
825         return strip.type in {'MOVIE', 'IMAGE', 'SCENE', 'META', 'MULTICAM'}
826
827     def draw_header(self, context):
828         strip = act_strip(context)
829
830         self.layout.prop(strip, "use_proxy", text="")
831
832     def draw(self, context):
833         layout = self.layout
834
835         strip = act_strip(context)
836
837         flow = layout.column_flow()
838         flow.prop(strip, "use_proxy_custom_directory")
839         flow.prop(strip, "use_proxy_custom_file")
840         if strip.proxy:
841             if strip.use_proxy_custom_directory and not strip.use_proxy_custom_file:
842                 flow.prop(strip.proxy, "directory")
843             if strip.use_proxy_custom_file:
844                 flow.prop(strip.proxy, "filepath")
845
846             row = layout.row()
847             row.prop(strip.proxy, "build_25")
848             row.prop(strip.proxy, "build_50")
849             row.prop(strip.proxy, "build_75")
850             row.prop(strip.proxy, "build_100")
851
852             col = layout.column()
853             col.label(text="Build JPEG quality")
854             col.prop(strip.proxy, "quality")
855
856             if strip.type == 'MOVIE':
857                 col = layout.column()
858                 col.label(text="Use timecode index:")
859
860                 col.prop(strip.proxy, "timecode")
861
862
863 class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
864     bl_label = "Scene Preview/Render"
865     bl_space_type = 'SEQUENCE_EDITOR'
866     bl_region_type = 'UI'
867
868     def draw(self, context):
869         layout = self.layout
870
871         render = context.scene.render
872
873         col = layout.column()
874         col.prop(render, "use_sequencer_gl_preview", text="Open GL Preview")
875         col = layout.column()
876         #col.active = render.use_sequencer_gl_preview
877         col.prop(render, "sequencer_gl_preview", text="")
878
879         row = col.row()
880         row.active = render.sequencer_gl_preview == 'SOLID'
881         row.prop(render, "use_sequencer_gl_textured_solid")
882
883
884 class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
885     bl_label = "View Settings"
886
887     def draw(self, context):
888         layout = self.layout
889
890         st = context.space_data
891
892         col = layout.column()
893         if st.display_mode == 'IMAGE':
894             col.prop(st, "draw_overexposed")
895             col.prop(st, "show_safe_margin")
896         elif st.display_mode == 'WAVEFORM':
897             col.prop(st, "show_separate_color")
898         col.prop(st, "proxy_render_size")
899
900
901 class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
902     bl_label = "Modifiers"
903
904     def draw(self, context):
905         layout = self.layout
906
907         strip = act_strip(context)
908         sequencer = context.scene.sequence_editor
909
910         layout.prop(strip, "use_linear_modifiers")
911
912         layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
913
914         for mod in strip.modifiers:
915             box = layout.box()
916
917             row = box.row()
918             row.prop(mod, "show_expanded", text="", emboss=False)
919             row.prop(mod, "name", text="")
920
921             row.prop(mod, "mute", text="")
922
923             sub = row.row(align=True)
924             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_UP')
925             props.name = mod.name
926             props.direction = 'UP'
927             props = sub.operator("sequencer.strip_modifier_move", text="", icon='TRIA_DOWN')
928             props.name = mod.name
929             props.direction = 'DOWN'
930
931             row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name
932
933             if mod.show_expanded:
934                 row = box.row()
935                 row.prop(mod, "input_mask_type", expand=True)
936
937                 if mod.input_mask_type == 'STRIP':
938                     box.prop_search(mod, "input_mask_strip", sequencer, "sequences", text="Mask")
939                 else:
940                     box.prop(mod, "input_mask_id")
941
942                 if mod.type == 'COLOR_BALANCE':
943                     box.prop(mod, "color_multiply")
944                     draw_color_balance(box, mod.color_balance)
945                 elif mod.type == 'CURVES':
946                     box.template_curve_mapping(mod, "curve_mapping", type='COLOR')
947                 elif mod.type == 'HUE_CORRECT':
948                     box.template_curve_mapping(mod, "curve_mapping", type='HUE')
949                 elif mod.type == 'BRIGHT_CONTRAST':
950                     col = box.column()
951                     col.prop(mod, "bright")
952                     col.prop(mod, "contrast")
953
954
955 if __name__ == "__main__":  # only for live edit.
956     bpy.utils.register_module(__name__)