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