# SPDX-FileCopyrightText: 2009-2023 Blender Authors # # SPDX-License-Identifier: GPL-2.0-or-later import bpy from bpy.types import ( Panel, ) from bpy.app.translations import ( contexts as i18n_contexts, pgettext_rpt as rpt_, ) from rna_prop_ui import PropertyPanel from bl_ui.utils import PresetPanel class StripButtonsPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = "strip" @classmethod def poll(cls, context): return context.active_strip is not None class StripColorTagPicker: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = "none" # Used as popover @classmethod def poll(cls, context): return context.active_strip is not None class STRIP_PT_effect_text_style_presets(PresetPanel, Panel): bl_label = "Text Style Presets" preset_subdir = "sequencer/text_style" preset_operator = "script.execute_preset" preset_add_operator = "sequencer.text_strip_style_preset_add" class STRIP_PT_color_tag_picker(StripColorTagPicker, Panel): bl_label = "Color Tag" bl_options = {'HIDE_HEADER'} def draw(self, _context): layout = self.layout row = layout.row(align=True) row.operator("sequencer.strip_color_tag_set", icon='X').color = 'NONE' for i in range(1, 10): icon = 'STRIP_COLOR_{:02d}'.format(i) row.operator("sequencer.strip_color_tag_set", icon=icon).color = 'COLOR_{:02d}'.format(i) class STRIP_PT_strip(StripButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} def draw(self, context): layout = self.layout strip = context.active_strip strip_type = strip.type if strip_type in { 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'MULTIPLY', 'GLOW', 'SPEED', 'MULTICAM', 'GAUSSIAN_BLUR', 'COLORMIX', }: icon_header = 'SHADERFX' elif strip_type in { 'CROSS', 'GAMMA_CROSS', 'WIPE', 'COMPOSITOR', }: icon_header = 'ARROW_LEFTRIGHT' elif strip_type == 'SCENE': icon_header = 'SCENE_DATA' elif strip_type == 'MOVIECLIP': icon_header = 'TRACKER' elif strip_type == 'MASK': icon_header = 'MOD_MASK' elif strip_type == 'MOVIE': icon_header = 'FILE_MOVIE' elif strip_type == 'SOUND': icon_header = 'FILE_SOUND' elif strip_type == 'IMAGE': icon_header = 'FILE_IMAGE' elif strip_type == 'COLOR': icon_header = 'COLOR' elif strip_type == 'TEXT': icon_header = 'FONT_DATA' elif strip_type == 'ADJUSTMENT': icon_header = 'COLOR' elif strip_type == 'META': icon_header = 'SEQ_STRIP_META' else: icon_header = 'SEQ_STRIP' row = layout.row(align=True) row.use_property_decorate = False row.label(text="", icon=icon_header) row.separator() row.prop(strip, "name", text="") sub = row.row(align=True) if strip.color_tag == 'NONE': sub.popover(panel="STRIP_PT_color_tag_picker", text="", icon='COLOR') else: icon = 'STRIP_' + strip.color_tag sub.popover(panel="STRIP_PT_color_tag_picker", text="", icon=icon) row.separator() row.prop(strip, "mute", toggle=True, icon_only=True, emboss=False) class STRIP_PT_adjust_crop(StripButtonsPanel, Panel): bl_label = "Crop" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type != 'SOUND' def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True layout.active = not strip.mute col = layout.column(align=True) col.prop(strip.crop, "min_x") col.prop(strip.crop, "max_x") col.prop(strip.crop, "max_y") col.prop(strip.crop, "min_y") def draw_compositor_effect_node_group_errors(layout, node_tree, strip_input_num): if not node_tree or not node_tree.interface: return float_input_sockets_num = 0 color_input_sockets_num = 0 output_sockets = [] for socket in node_tree.interface.items_tree: if socket.item_type == 'SOCKET': if socket.in_out == 'INPUT' and socket.socket_type == 'NodeSocketColor': color_input_sockets_num += 1 elif socket.in_out == 'INPUT' and socket.socket_type == 'NodeSocketFloat': float_input_sockets_num += 1 elif socket.in_out == 'OUTPUT': output_sockets.append(socket) if color_input_sockets_num < strip_input_num: layout.label( text=rpt_("Node group must have at least {:d} Color input(s).").format(strip_input_num), icon='STATUS_ERROR', translate=False, ) if float_input_sockets_num == 0: layout.label( text=rpt_("Node group does not have an input of type Float. Fade is unused."), icon='STATUS_ERROR', translate=False, ) if len(output_sockets) < 1: layout.label( text=rpt_("Node group must have an output."), icon='STATUS_ERROR', translate=False, ) elif output_sockets[0].socket_type != 'NodeSocketColor': layout.label( text=rpt_("The first node group output must have the Color type."), icon='STATUS_ERROR', translate=False, ) class STRIP_PT_effect(StripButtonsPanel, Panel): bl_label = "Effect Strip" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type in { 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'COMPOSITOR', 'MULTIPLY', 'WIPE', 'GLOW', 'COLOR', 'SPEED', 'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT', 'COLORMIX', } def draw_header_preset(self, context): strip = context.active_strip if strip.type == 'TEXT': STRIP_PT_effect_text_style_presets.draw_panel_header(self.layout) def draw(self, context): layout = self.layout layout.use_property_split = True strip = context.active_strip layout.active = not strip.mute strip_type = strip.type if strip_type == 'COMPOSITOR': layout.template_ID(strip, "node_group", new="node.new_compositor_sequencer_node_group") draw_compositor_effect_node_group_errors(layout, strip.node_group, strip.input_count) if strip.input_count > 0: col = layout.column() row = col.row() row.prop(strip, "input_1") if strip.input_count > 1: is_transition = strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'COMPOSITOR'} if not is_transition: row.operator("sequencer.swap_inputs", text="", icon='SORT_ASC') row = col.row() row.prop(strip, "input_2") if not is_transition: row.operator("sequencer.swap_inputs", text="", icon='SORT_DESC') if strip_type == 'COLOR': layout.template_color_picker(strip, "color", value_slider=True, cubic=True) layout.prop(strip, "color", text="") elif strip_type == 'WIPE': col = layout.column() col.prop(strip, "transition_type") col.alignment = 'RIGHT' col.row().prop(strip, "direction", expand=True) col = layout.column() col.prop(strip, "blur_width", slider=True) if strip.transition_type in {'SINGLE', 'DOUBLE'}: col.prop(strip, "angle") elif strip_type == 'GLOW': flow = layout.column_flow() flow.prop(strip, "threshold", slider=True) flow.prop(strip, "clamp", slider=True) flow.prop(strip, "boost_factor") flow.prop(strip, "blur_radius") flow.prop(strip, "quality", slider=True) flow.prop(strip, "use_only_boost") elif strip_type == 'SPEED': col = layout.column(align=True) col.prop(strip, "speed_control", text="Speed Control") if strip.speed_control == 'MULTIPLY': col.prop(strip, "speed_factor", text=" ") elif strip.speed_control == 'LENGTH': col.prop(strip, "speed_length", text=" ") elif strip.speed_control == 'FRAME_NUMBER': col.prop(strip, "speed_frame_number", text=" ") row = layout.row(align=True) row.enabled = strip.speed_control != 'STRETCH' row = layout.row(align=True, heading="Interpolation") row.prop(strip, "use_frame_interpolate", text="") elif strip_type == 'MULTICAM': col = layout.column(align=True) strip_channel = strip.channel col.prop(strip, "multicam_source", text="Source Channel") # The multicam strip needs at least 2 strips to be useful if strip_channel > 2: BT_ROW = 4 col.label(text="Cut To") row = col.row() for i in range(1, strip_channel): if (i % BT_ROW) == 1: row = col.row(align=True) # Workaround - .enabled has to have a separate UI block to work if i == strip.multicam_source: sub = row.row(align=True) sub.enabled = False sub.operator("sequencer.split_multicam", text="{:d}".format(i), translate=False).camera = i else: sub_1 = row.row(align=True) sub_1.enabled = True sub_1.operator("sequencer.split_multicam", text="{:d}".format(i), translate=False).camera = i if strip.channel > BT_ROW and (strip_channel - 1) % BT_ROW: for i in range(strip.channel, strip_channel + ((BT_ROW + 1 - strip_channel) % BT_ROW)): row.label(text="") else: col.separator() col.label(text="Two or more channels are needed below this strip", icon='STATUS_INFO') elif strip_type == 'TEXT': layout = self.layout col = layout.column() col.textbox_with_state(strip, "text", textbox_state=strip.textbox_state) layout.prop(strip, "wrap_width", text="Wrap Width") col = layout.column(align=True) if strip_type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'COMPOSITOR'}: col.prop(strip, "use_default_fade", text="Default Fade") if not strip.use_default_fade: col.prop(strip, "effect_fader", text="Effect Fader") elif strip_type == 'GAUSSIAN_BLUR': col = layout.column(align=True) col.prop(strip, "size_x", text="Size X") col.prop(strip, "size_y", text="Y") elif strip_type == 'COLORMIX': layout.prop(strip, "blend_effect", text="Blend Mode") row = layout.row(align=True) row.prop(strip, "factor", slider=True) if strip_type == 'COMPOSITOR': layout.template_compositor_strip_inputs(strip) class STRIP_PT_effect_text_layout(StripButtonsPanel, Panel): bl_label = "Layout" bl_parent_id = "STRIP_PT_effect" @classmethod def poll(cls, context): strip = context.active_strip return strip.type == 'TEXT' def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True col = layout.column() col.prop(strip, "location", text="Location") col.prop(strip, "alignment_x", text="Alignment X") col.prop(strip, "anchor_x", text="Anchor X") col.prop(strip, "anchor_y", text="Y") class STRIP_PT_effect_text_style(StripButtonsPanel, Panel): bl_label = "Style" bl_parent_id = "STRIP_PT_effect" @classmethod def poll(cls, context): strip = context.active_strip return strip.type == 'TEXT' def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True col = layout.column() row = col.row(align=True) row.use_property_decorate = False row.template_ID(strip, "font", open="font.open", unlink="font.unlink") row.prop(strip, "use_bold", text="", icon='BOLD') row.prop(strip, "use_italic", text="", icon='ITALIC') col.prop(strip, "font_size") row = col.row() if strip.use_absolute_line_spacing: row.prop(strip, "abs_space_line", text="Line Spacing") else: row.prop(strip, "space_line", text="Line Spacing") row.prop(strip, "use_absolute_line_spacing", text="", icon='FIXED_SIZE') col.prop(strip, "color") class STRIP_PT_effect_text_outline(StripButtonsPanel, Panel): bl_label = "Outline" bl_options = {'DEFAULT_CLOSED'} bl_parent_id = "STRIP_PT_effect_text_style" @classmethod def poll(cls, context): strip = context.active_strip return strip.type == 'TEXT' def draw_header(self, context): strip = context.active_strip layout = self.layout layout.prop(strip, "use_outline", text="") def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True col = layout.column() col.prop(strip, "outline_color", text="Color") col.prop(strip, "outline_width", text="Width") col.active = strip.use_outline and (not strip.mute) class STRIP_PT_effect_text_shadow(StripButtonsPanel, Panel): bl_label = "Shadow" bl_options = {'DEFAULT_CLOSED'} bl_parent_id = "STRIP_PT_effect_text_style" @classmethod def poll(cls, context): strip = context.active_strip return strip.type == 'TEXT' def draw_header(self, context): strip = context.active_strip layout = self.layout layout.prop(strip, "use_shadow", text="") def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True col = layout.column() col.prop(strip, "shadow_color", text="Color") col.prop(strip, "shadow_angle", text="Angle") col.prop(strip, "shadow_offset", text="Offset") col.prop(strip, "shadow_blur", text="Blur") col.active = strip.use_shadow and (not strip.mute) class STRIP_PT_effect_text_box(StripButtonsPanel, Panel): bl_label = "Box" bl_translation_context = i18n_contexts.id_sequence bl_options = {'DEFAULT_CLOSED'} bl_parent_id = "STRIP_PT_effect_text_style" @classmethod def poll(cls, context): strip = context.active_strip return strip.type == 'TEXT' def draw_header(self, context): strip = context.active_strip layout = self.layout layout.prop(strip, "use_box", text="") def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True col = layout.column() col.prop(strip, "box_color", text="Color") col.prop(strip, "box_margin", text="Margin") col.prop(strip, "box_roundness", text="Roundness") col.active = strip.use_box and (not strip.mute) class STRIP_PT_source(StripButtonsPanel, Panel): bl_label = "Source" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type in {'MOVIE', 'IMAGE', 'SOUND'} def draw(self, context): layout = self.layout layout.use_property_split = True layout.use_property_decorate = False scene = context.sequencer_scene strip = context.active_strip strip_type = strip.type layout.active = not strip.mute # Draw a filename if we have one. if strip_type == 'SOUND': sound = strip.sound layout.template_ID(strip, "sound", open="sound.open") if sound is not None: col = layout.column() col.prop(sound, "filepath", text="") col.alignment = 'RIGHT' sub = col.column(align=True) split = sub.split(factor=0.5, align=True) split.alignment = 'RIGHT' if sound.packed_file: split.label(text="Unpack") split.operator("sound.unpack", icon='PACKAGE', text="") else: split.label(text="Pack") split.operator("sound.pack", icon='UGLYPACKAGE', text="") layout.prop(sound, "use_memory_cache") col = layout.box() col = col.column(align=True) split = col.split(factor=0.5, align=False) split.alignment = 'RIGHT' split.label(text="Sample Rate") split.alignment = 'LEFT' if sound.samplerate <= 0: split.label(text="Unknown") else: split.label(text="{:d} Hz".format(sound.samplerate), translate=False) split = col.split(factor=0.5, align=False) split.alignment = 'RIGHT' split.label(text="Channels") split.alignment = 'LEFT' # FIXME(@campbellbarton): this is ugly, we may want to support a way of showing a label from an enum. channel_enum_items = sound.bl_rna.properties["channels"].enum_items split.label(text=channel_enum_items[channel_enum_items.find(sound.channels)].name) del channel_enum_items else: if strip_type == 'IMAGE': col = layout.column() col.prop(strip, "directory", text="") # Current element for the filename. elem = strip.strip_elem_from_frame(scene.frame_current) if elem: col.prop(elem, "filename", text="") # strip.elements[0] could be a fallback col.prop_with_menu( strip.colorspace_settings, "name", text="Color Space", menu="UI_MT_color_space_select") col.prop(strip, "alpha_mode", text="Alpha") sub = col.column(align=True) sub.operator("sequencer.change_path", text="Change Data/Files", icon='FILEBROWSER').filter_image = True else: # elif strip_type == 'MOVIE': elem = strip.elements[0] col = layout.column() col.prop(strip, "filepath", text="") col.prop_with_menu( strip.colorspace_settings, "name", text="Color Space", menu="UI_MT_color_space_select") col.prop(strip, "stream_index") col.prop(strip, "use_deinterlace") if scene.render.use_multiview: layout.prop(strip, "use_multiview") col = layout.column() col.active = strip.use_multiview col.row().prop(strip, "views_format", expand=True) box = col.box() box.active = strip.views_format == 'STEREO_3D' box.template_image_stereo_3d(strip.stereo_3d_format) # Resolution. col = layout.box() col = col.column(align=True) split = col.split(factor=0.5, align=False) split.alignment = 'RIGHT' split.label(text="Resolution") size = (elem.orig_width, elem.orig_height) if elem else (0, 0) if size[0] and size[1]: split.alignment = 'LEFT' split.label(text="{:d}x{:d}".format(*size), translate=False) else: split.label(text="None") # FPS if elem.orig_fps: split = col.split(factor=0.5, align=False) split.alignment = 'RIGHT' split.label(text="FPS") split.alignment = 'LEFT' split.label(text="{:.2f}".format(elem.orig_fps), translate=False) class STRIP_PT_movie_clip(StripButtonsPanel, Panel): bl_label = "Movie Clip" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type == 'MOVIECLIP' def draw(self, context): layout = self.layout layout.use_property_split = True layout.use_property_decorate = False strip = context.active_strip layout.active = not strip.mute layout.template_ID(strip, "clip") if strip.type == 'MOVIECLIP': col = layout.column(heading="Use") col.prop(strip, "stabilize2d", text="2D Stabilized Clip") col.prop(strip, "undistort", text="Undistorted Clip") clip = strip.clip if clip: sta = clip.frame_start end = clip.frame_start + clip.frame_duration layout.label( text=rpt_("Original frame range: {:d}-{:d} ({:d})").format(sta, end, end - sta + 1), translate=False, ) class STRIP_PT_scene(StripButtonsPanel, Panel): bl_label = "Scene" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return (strip.type == 'SCENE') def draw(self, context): strip = context.active_strip scene = strip.scene layout = self.layout layout.use_property_split = True layout.use_property_decorate = False layout.active = not strip.mute layout.template_ID(strip, "scene", text="Scene", new="scene.new_sequencer") if scene: row = layout.row() row.enabled = (strip.scene_input == 'CAMERA') row.template_search(strip, "view_layer", scene, "view_layers", text="View Layer") layout.prop(strip, "scene_input", text="Input") if strip.scene_input == 'CAMERA': layout.template_ID(strip, "scene_camera", text="Camera") if strip.scene_input == 'CAMERA': layout = layout.column(heading="Show") layout.prop(strip, "use_annotations", text="Annotations") if scene: # Warning, this is not a good convention to follow. # Expose here because setting the alpha from the "Render" menu is very inconvenient. layout.prop(scene.render, "film_transparent") class STRIP_PT_scene_sound(StripButtonsPanel, Panel): bl_label = "Sound" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return (strip.type == 'SCENE') def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True layout.use_property_decorate = False layout.active = not strip.mute col = layout.column() col.use_property_decorate = True split = col.split(factor=col.property_split_factor) split.alignment = 'RIGHT' split.label(text="Strip Volume", text_ctxt=i18n_contexts.id_sound) split.prop(strip, "volume", text="") col.use_property_decorate = False class STRIP_PT_mask(StripButtonsPanel, Panel): bl_label = "Mask" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return (strip.type == 'MASK') def draw(self, context): layout = self.layout layout.use_property_split = True strip = context.active_strip layout.active = not strip.mute layout.template_ID(strip, "mask") mask = strip.mask if mask: sta = mask.frame_start end = mask.frame_end layout.label( text=rpt_("Original frame range: {:d}-{:d} ({:d})").format(sta, end, end - sta + 1), translate=False, ) class STRIP_PT_time(StripButtonsPanel, Panel): bl_label = "Time" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type def draw_header_preset(self, context): layout = self.layout layout.alignment = 'RIGHT' strip = context.active_strip layout.prop(strip, "lock", text="", icon_only=True, emboss=False) def draw(self, context): from bpy.utils import smpte_from_frame layout = self.layout layout.use_property_split = False layout.use_property_decorate = False scene = context.sequencer_scene frame_current = scene.frame_current strip = context.active_strip is_effect = isinstance(strip, bpy.types.EffectStrip) # Get once. content_start = strip.content_start content_duration = strip.content_duration content_end = strip.content_end left_handle = strip.left_handle duration = strip.duration right_handle = strip.right_handle length_list = ( str(round(left_handle, 0)), str(round(duration, 0)), str(round(right_handle, 0)), ) if not is_effect: length_list = length_list + ( str(round(strip.content_trim_start, 0)), str(round(strip.content_trim_end, 0)), str(round(content_start, 0)), str(round(content_duration, 0)), str(round(content_end, 0)), ) max_length = max(len(x) for x in length_list) max_factor = (1.9 - max_length) / 30 factor = 0.45 layout.enabled = not strip.lock layout.active = not strip.mute sub = layout.row(align=True) split = sub.split(factor=factor + max_factor) split.alignment = 'RIGHT' split.label(text="Channel") split.prop(strip, "channel", text="") layout.alignment = 'RIGHT' sub = layout.column(align=True) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Left Handle") split.prop(strip, "left_handle", text=smpte_from_frame(left_handle)) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Strip Duration") split.prop(strip, "duration", text=smpte_from_frame(duration)) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Right Handle") split.prop(strip, "right_handle", text=smpte_from_frame(right_handle)) if not is_effect: sub = layout.column(align=True) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Content Start") split.prop(strip, "content_start", text=smpte_from_frame(content_start)) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Duration") split.prop(strip, "content_duration", text=smpte_from_frame(content_duration)) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="End") split.prop(strip, "content_end", text=smpte_from_frame(content_end)) layout.alignment = 'RIGHT' sub = layout.column(align=True) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Content Trim Start") split.prop(strip, "content_trim_start", text=smpte_from_frame(strip.content_trim_start)) split = sub.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="End") split.prop(strip, "content_trim_end", text=smpte_from_frame(strip.content_trim_end)) if strip.type == 'SOUND': sub2 = layout.column(align=True) split = sub2.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Sound Offset", text_ctxt=i18n_contexts.id_sound) split.prop(strip, "sound_offset", text="") col = layout.column(align=True) col = col.box() col.active = ( (frame_current >= left_handle) and (frame_current <= left_handle + duration) ) split = col.split(factor=factor + max_factor, align=True) split.alignment = 'RIGHT' split.label(text="Playhead Offset") split = split.split(factor=factor + 0.3 + max_factor, align=True) frame_display = frame_current - left_handle split.label(text="{:>14s}".format(smpte_from_frame(frame_display)), translate=False) split.alignment = 'RIGHT' split.label(text=str(frame_display) + " ") if strip.type == 'SCENE': scene = strip.scene if scene: sta = scene.frame_start end = scene.frame_end split = col.split(factor=factor + max_factor) split.alignment = 'RIGHT' split.label(text="Scene Frame Range") split.alignment = 'LEFT' split.label(text="{:d}-{:d} ({:d})".format(sta, end, end - sta + 1), translate=False) if not is_effect: sub = layout.row(align=True) split = sub.split(factor=factor + max_factor) split.alignment = 'RIGHT' split.label(text="") split.prop(strip, "show_retiming_keys") class STRIP_PT_adjust_sound(StripButtonsPanel, Panel): bl_label = "Sound" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type in {'SOUND', 'META', } def draw(self, context): layout = self.layout strip = context.active_strip sound = getattr(strip, "sound", None) layout.active = not strip.mute if sound is not None or strip.type == 'META': layout.use_property_split = True col = layout.column() split = col.split(factor=col.property_split_factor) split.alignment = 'RIGHT' split.label(text="Volume", text_ctxt=i18n_contexts.id_sound) split.prop(strip, "volume", text="") if sound is not None: layout.use_property_split = False col = layout.column() split = col.split(factor=col.property_split_factor) split.label(text="") split.prop(sound, "use_mono") layout.use_property_split = True col = layout.column() audio_channels = context.sequencer_scene.render.ffmpeg.audio_channels pan_enabled = sound.use_mono and audio_channels != 'MONO' pan_text = "{:.2f}°".format(strip.pan * 90.0) split = col.split(factor=col.property_split_factor) split.alignment = 'RIGHT' split.label(text="Pan", text_ctxt=i18n_contexts.id_sound) split.prop(strip, "pan", text="") split.enabled = pan_enabled if audio_channels not in {'MONO', 'STEREO'}: split = col.split(factor=col.property_split_factor) split.alignment = 'RIGHT' split.label(text="Pan Angle") split.enabled = pan_enabled subsplit = split.row() subsplit.alignment = 'CENTER' subsplit.label(text=pan_text) subsplit.label(text=" ") # Compensate for no decorate. subsplit.enabled = pan_enabled layout.use_property_split = False col = layout.column() split = col.split(factor=col.property_split_factor) split.label(text="") split.prop(strip, "pitch_correction") split = col.split(factor=col.property_split_factor) split.label(text="") split.prop(strip, "show_waveform") class STRIP_PT_adjust_comp(StripButtonsPanel, Panel): bl_label = "Compositing" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type != 'SOUND' def draw(self, context): layout = self.layout layout.use_property_split = True strip = context.active_strip layout.active = not strip.mute col = layout.column() col.prop(strip, "blend_type", text="Blend") col.prop(strip, "blend_alpha", text="Opacity", slider=True) class STRIP_PT_adjust_transform(StripButtonsPanel, Panel): bl_label = "Transform" @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type != 'SOUND' def draw(self, context): strip = context.active_strip layout = self.layout layout.use_property_split = True layout.active = not strip.mute col = layout.column(align=True) col.prop(strip.transform, "filter", text="Filter") col = layout.column(align=True) col.prop(strip.transform, "offset_x", text="Position X") col.prop(strip.transform, "offset_y", text="Y") if strip.type == 'COLOR': col = layout.column(align=True) col.prop(strip, "width", text="Width") col.prop(strip, "height", text="Height") col = layout.column(align=True) col.prop(strip.transform, "scale_x", text="Scale X") col.prop(strip.transform, "scale_y", text="Y") col = layout.column(align=True) col.prop(strip.transform, "rotation", text="Rotation") col = layout.column(align=True) col.prop(strip.transform, "origin") col = layout.column(heading="Mirror", align=True, heading_ctxt=i18n_contexts.id_image) col.prop(strip, "use_flip_x", text="X", toggle=True) col.prop(strip, "use_flip_y", text="Y", toggle=True) class STRIP_PT_adjust_video(StripButtonsPanel, Panel): bl_label = "Video" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type in { 'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK', 'META', } def draw(self, context): layout = self.layout layout.use_property_split = True col = layout.column() strip = context.active_strip layout.active = not strip.mute col.prop(strip, "strobe") col.prop(strip, "use_reverse_frames") class STRIP_PT_adjust_color(StripButtonsPanel, Panel): bl_label = "Color" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): strip = context.active_strip if not strip: return False return strip.type in { 'MOVIE', 'IMAGE', 'SCENE', 'MOVIECLIP', 'MASK', 'META', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'COMPOSITOR', 'WIPE', 'GLOW', 'COLOR', 'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX', } def draw(self, context): layout = self.layout layout.use_property_split = True strip = context.active_strip layout.active = not strip.mute col = layout.column() col.prop(strip, "color_saturation", text="Saturation") col.prop(strip, "color_multiply", text="Multiply") col.prop(strip, "multiply_alpha") col.prop(strip, "use_float", text="Convert to Float") class STRIP_PT_custom_props(StripButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = { 'BLENDER_RENDER', 'BLENDER_WORKBENCH', } _context_path = "active_strip" _property_type = (bpy.types.Strip,) classes = ( STRIP_PT_color_tag_picker, STRIP_PT_strip, STRIP_PT_effect, STRIP_PT_scene, STRIP_PT_scene_sound, STRIP_PT_mask, STRIP_PT_effect_text_style, STRIP_PT_effect_text_style_presets, STRIP_PT_effect_text_outline, STRIP_PT_effect_text_shadow, STRIP_PT_effect_text_box, STRIP_PT_effect_text_layout, STRIP_PT_movie_clip, STRIP_PT_adjust_comp, STRIP_PT_adjust_transform, STRIP_PT_adjust_crop, STRIP_PT_adjust_video, STRIP_PT_adjust_color, STRIP_PT_adjust_sound, STRIP_PT_time, STRIP_PT_source, STRIP_PT_custom_props, ) if __name__ == "__main__": # only for live edit. from bpy.utils import register_class for cls in classes: register_class(cls)