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