VSE: Move Strip properties to Properties editor
Goal of this PR is mainly to improve flexibility and of VSE layout and screen space efficiency. Previously, strip properties were displayed in timeline sidebar. This was limiting, because if you want to display as much properties as possible, the timeline area had to be taller, but this was at the expense of space available for preview. However there is plenty of space in properties editor, which is mostly unused in VSE. Therefore strip properties were moved to the properties editor. ID pinning and path displayed in top section aren't drawn, since strip is not an ID and can not be pinned. Since there is more space for properties, various panels are changed to be open by default. Mainly transform and time panels, since they are used often. There is one minor change: The waveform display property of sound strip was previously hidden, if timeline area had per strip waveform display overlay set. This is no longer possible to do and the property is always visible. Pull Request: https://projects.blender.org/blender/blender/pulls/140395
This commit is contained in:
committed by
Richard Antalik
parent
258f449783
commit
f385327442
@@ -60,6 +60,8 @@ _modules = [
|
||||
"properties_texture",
|
||||
"properties_world",
|
||||
"properties_collection",
|
||||
"properties_strip",
|
||||
"properties_strip_modifier",
|
||||
"generic_ui_list",
|
||||
|
||||
# Generic Space Modules
|
||||
|
||||
1056
scripts/startup/bl_ui/properties_strip.py
Normal file
1056
scripts/startup/bl_ui/properties_strip.py
Normal file
@@ -0,0 +1,1056 @@
|
||||
# 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
|
||||
|
||||
|
||||
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_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',
|
||||
}:
|
||||
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_SEQUENCER'
|
||||
|
||||
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")
|
||||
|
||||
|
||||
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',
|
||||
'MULTIPLY',
|
||||
'WIPE',
|
||||
'GLOW',
|
||||
'COLOR',
|
||||
'SPEED',
|
||||
'MULTICAM',
|
||||
'GAUSSIAN_BLUR',
|
||||
'TEXT',
|
||||
'COLORMIX',
|
||||
}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
strip = context.active_strip
|
||||
|
||||
layout.active = not strip.mute
|
||||
|
||||
if strip.input_count > 0:
|
||||
col = layout.column()
|
||||
row = col.row()
|
||||
row.prop(strip, "input_1")
|
||||
|
||||
if strip.input_count > 1:
|
||||
row.operator("sequencer.swap_inputs", text="", icon='SORT_ASC')
|
||||
row = col.row()
|
||||
row.prop(strip, "input_2")
|
||||
row.operator("sequencer.swap_inputs", text="", icon='SORT_DESC')
|
||||
|
||||
strip_type = strip.type
|
||||
|
||||
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='INFO')
|
||||
|
||||
elif strip_type == 'TEXT':
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.scale_x = 1.3
|
||||
col.scale_y = 1.3
|
||||
col.use_property_split = False
|
||||
col.prop(strip, "text", text="")
|
||||
col.use_property_split = True
|
||||
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'}:
|
||||
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)
|
||||
|
||||
|
||||
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")
|
||||
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(strip.colorspace_settings, "name", text="Color Space")
|
||||
|
||||
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(strip.colorspace_settings, "name", text="Color Space")
|
||||
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")
|
||||
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=0.4)
|
||||
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.
|
||||
frame_start = strip.frame_start
|
||||
frame_final_start = strip.frame_final_start
|
||||
frame_final_end = strip.frame_final_end
|
||||
frame_final_duration = strip.frame_final_duration
|
||||
frame_offset_start = strip.frame_offset_start
|
||||
frame_offset_end = strip.frame_offset_end
|
||||
|
||||
length_list = (
|
||||
str(round(frame_start, 0)),
|
||||
str(round(frame_final_end, 0)),
|
||||
str(round(frame_final_duration, 0)),
|
||||
str(round(frame_offset_start, 0)),
|
||||
str(round(frame_offset_end, 0)),
|
||||
)
|
||||
|
||||
if not is_effect:
|
||||
length_list = length_list + (
|
||||
str(round(strip.animation_offset_start, 0)),
|
||||
str(round(strip.animation_offset_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="")
|
||||
split.prop(strip, "show_retiming_keys")
|
||||
|
||||
sub = layout.row(align=True)
|
||||
split = sub.split(factor=factor + max_factor)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Channel")
|
||||
split.prop(strip, "channel", text="")
|
||||
|
||||
sub = layout.column(align=True)
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Start")
|
||||
split.prop(strip, "frame_start", text=smpte_from_frame(frame_start))
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Duration")
|
||||
split.prop(strip, "frame_final_duration", text=smpte_from_frame(frame_final_duration))
|
||||
|
||||
# Use label, editing this value from the UI allows negative values,
|
||||
# users can adjust duration.
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split = split.split(factor=factor + 0.3 + max_factor, align=True)
|
||||
split.label(text="{:>14s}".format(smpte_from_frame(frame_final_end)), translate=False)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text=str(frame_final_end) + " ")
|
||||
|
||||
if not is_effect:
|
||||
|
||||
layout.alignment = 'RIGHT'
|
||||
sub = layout.column(align=True)
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Strip Offset Start")
|
||||
split.prop(strip, "frame_offset_start", text=smpte_from_frame(frame_offset_start))
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split.prop(strip, "frame_offset_end", text=smpte_from_frame(frame_offset_end))
|
||||
|
||||
layout.alignment = 'RIGHT'
|
||||
sub = layout.column(align=True)
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Hold Offset Start")
|
||||
split.prop(strip, "animation_offset_start", text=smpte_from_frame(strip.animation_offset_start))
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split.prop(strip, "animation_offset_end", text=smpte_from_frame(strip.animation_offset_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 >= frame_final_start) and
|
||||
(frame_current <= frame_final_start + frame_final_duration)
|
||||
)
|
||||
|
||||
split = col.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Current Frame")
|
||||
split = split.split(factor=factor + 0.3 + max_factor, align=True)
|
||||
frame_display = frame_current - frame_final_start
|
||||
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="Original Frame Range")
|
||||
split.alignment = 'LEFT'
|
||||
split.label(text="{:d}-{:d} ({:d})".format(sta, end, end - sta + 1), translate=False)
|
||||
|
||||
|
||||
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 == 'SOUND'
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
strip = context.active_strip
|
||||
sound = strip.sound
|
||||
|
||||
layout.active = not strip.mute
|
||||
|
||||
if sound is not None:
|
||||
layout.use_property_split = True
|
||||
col = layout.column()
|
||||
|
||||
split = col.split(factor=0.4)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Volume", text_ctxt=i18n_contexts.id_sound)
|
||||
split.prop(strip, "volume", text="")
|
||||
|
||||
layout.use_property_split = False
|
||||
col = layout.column()
|
||||
|
||||
split = col.split(factor=0.4)
|
||||
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=0.4)
|
||||
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=0.4)
|
||||
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=0.4)
|
||||
split.label(text="")
|
||||
split.prop(strip, "pitch_correction")
|
||||
|
||||
split = col.split(factor=0.4)
|
||||
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")
|
||||
|
||||
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', 'ADD', 'SUBTRACT', 'ALPHA_OVER',
|
||||
'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY',
|
||||
'WIPE', 'GLOW', 'COLOR', 'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX',
|
||||
}
|
||||
|
||||
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',
|
||||
'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_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)
|
||||
56
scripts/startup/bl_ui/properties_strip_modifier.py
Normal file
56
scripts/startup/bl_ui/properties_strip_modifier.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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
|
||||
|
||||
|
||||
class StripModButtonsPanel:
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "strip_modifier"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_strip is not None
|
||||
|
||||
|
||||
class STRIP_PT_modifiers(StripModButtonsPanel, Panel):
|
||||
bl_label = "Modifiers"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
strip = context.active_strip
|
||||
ed = context.sequencer_scene.sequence_editor
|
||||
if strip.type == 'SOUND':
|
||||
sound = strip.sound
|
||||
else:
|
||||
sound = None
|
||||
|
||||
if sound is None:
|
||||
layout.prop(strip, "use_linear_modifiers", text="Linear Modifiers")
|
||||
|
||||
layout.operator("wm.call_menu", text="Add Modifier", icon='ADD').name = "SEQUENCER_MT_modifier_add"
|
||||
|
||||
layout.template_strip_modifiers()
|
||||
|
||||
|
||||
classes = (
|
||||
STRIP_PT_modifiers,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
@@ -32,7 +32,9 @@ class PROPERTIES_HT_header(Header):
|
||||
space.show_properties_bone or
|
||||
space.show_properties_bone_constraints or
|
||||
space.show_properties_material or
|
||||
space.show_properties_texture
|
||||
space.show_properties_texture or
|
||||
space.show_properties_strip or
|
||||
space.show_properties_strip_modifier
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
@@ -122,6 +124,8 @@ class PROPERTIES_PT_options(Panel):
|
||||
("show_properties_bone_constraints", "Bone Constraints", 'CONSTRAINT_BONE'),
|
||||
("show_properties_material", "Material", 'MATERIAL'),
|
||||
("show_properties_texture", "Texture", 'TEXTURE'),
|
||||
("show_properties_strip", "Strip", 'SEQ_SEQUENCER'),
|
||||
("show_properties_strip_modifier", "Strip Modifiers", 'SEQ_STRIP_MODIFIER')
|
||||
]
|
||||
|
||||
col = layout.column(align=True)
|
||||
|
||||
@@ -1617,7 +1617,6 @@ class SequencerColorTagPicker:
|
||||
|
||||
class SEQUENCER_PT_color_tag_picker(SequencerColorTagPicker, Panel):
|
||||
bl_label = "Color Tag"
|
||||
bl_category = "Strip"
|
||||
bl_options = {'HIDE_HEADER', 'INSTANCED'}
|
||||
|
||||
def draw(self, _context):
|
||||
@@ -1640,1022 +1639,6 @@ class SEQUENCER_MT_color_tag_picker(SequencerColorTagPicker, Menu):
|
||||
row.operator_enum("sequencer.strip_color_tag_set", "color", icon_only=True)
|
||||
|
||||
|
||||
class SEQUENCER_PT_strip(SequencerButtonsPanel, Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
bl_category = "Strip"
|
||||
|
||||
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',
|
||||
}:
|
||||
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_SEQUENCER'
|
||||
|
||||
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="SEQUENCER_PT_color_tag_picker", text="", icon='COLOR')
|
||||
else:
|
||||
icon = 'STRIP_' + strip.color_tag
|
||||
sub.popover(panel="SEQUENCER_PT_color_tag_picker", text="", icon=icon)
|
||||
|
||||
row.separator()
|
||||
row.prop(strip, "mute", toggle=True, icon_only=True, emboss=False)
|
||||
|
||||
|
||||
class SEQUENCER_PT_adjust_crop(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Crop"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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")
|
||||
|
||||
|
||||
class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Effect Strip"
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
strip = context.active_strip
|
||||
if not strip:
|
||||
return False
|
||||
|
||||
return strip.type in {
|
||||
'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
|
||||
'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'WIPE', 'GLOW', 'COLOR', 'SPEED',
|
||||
'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT', 'COLORMIX',
|
||||
}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
strip = context.active_strip
|
||||
|
||||
layout.active = not strip.mute
|
||||
|
||||
if strip.input_count > 0:
|
||||
col = layout.column()
|
||||
row = col.row()
|
||||
row.prop(strip, "input_1")
|
||||
|
||||
if strip.input_count > 1:
|
||||
row.operator("sequencer.swap_inputs", text="", icon='SORT_ASC')
|
||||
row = col.row()
|
||||
row.prop(strip, "input_2")
|
||||
row.operator("sequencer.swap_inputs", text="", icon='SORT_DESC')
|
||||
|
||||
strip_type = strip.type
|
||||
|
||||
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='INFO')
|
||||
|
||||
elif strip_type == 'TEXT':
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.scale_x = 1.3
|
||||
col.scale_y = 1.3
|
||||
col.use_property_split = False
|
||||
col.prop(strip, "text", text="")
|
||||
col.use_property_split = True
|
||||
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'}:
|
||||
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)
|
||||
|
||||
|
||||
class SEQUENCER_PT_effect_text_layout(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Layout"
|
||||
bl_parent_id = "SEQUENCER_PT_effect"
|
||||
bl_category = "Strip"
|
||||
|
||||
@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 SEQUENCER_PT_effect_text_style(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Style"
|
||||
bl_parent_id = "SEQUENCER_PT_effect"
|
||||
bl_category = "Strip"
|
||||
|
||||
@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")
|
||||
col.prop(strip, "color")
|
||||
|
||||
|
||||
class SEQUENCER_PT_effect_text_outline(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Outline"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
bl_parent_id = "SEQUENCER_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 SEQUENCER_PT_effect_text_shadow(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Shadow"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
bl_parent_id = "SEQUENCER_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 SEQUENCER_PT_effect_text_box(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Box"
|
||||
bl_translation_context = i18n_contexts.id_sequence
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
bl_parent_id = "SEQUENCER_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 SEQUENCER_PT_source(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Source"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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(strip.colorspace_settings, "name", text="Color Space")
|
||||
|
||||
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(strip.colorspace_settings, "name", text="Color Space")
|
||||
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 SEQUENCER_PT_movie_clip(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Movie Clip"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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 SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Scene"
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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")
|
||||
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 SEQUENCER_PT_scene_sound(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Sound"
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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=0.4)
|
||||
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 SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Mask"
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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 SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Time"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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.
|
||||
frame_start = strip.frame_start
|
||||
frame_final_start = strip.frame_final_start
|
||||
frame_final_end = strip.frame_final_end
|
||||
frame_final_duration = strip.frame_final_duration
|
||||
frame_offset_start = strip.frame_offset_start
|
||||
frame_offset_end = strip.frame_offset_end
|
||||
|
||||
length_list = (
|
||||
str(round(frame_start, 0)),
|
||||
str(round(frame_final_end, 0)),
|
||||
str(round(frame_final_duration, 0)),
|
||||
str(round(frame_offset_start, 0)),
|
||||
str(round(frame_offset_end, 0)),
|
||||
)
|
||||
|
||||
if not is_effect:
|
||||
length_list = length_list + (
|
||||
str(round(strip.animation_offset_start, 0)),
|
||||
str(round(strip.animation_offset_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="")
|
||||
split.prop(strip, "show_retiming_keys")
|
||||
|
||||
sub = layout.row(align=True)
|
||||
split = sub.split(factor=factor + max_factor)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Channel")
|
||||
split.prop(strip, "channel", text="")
|
||||
|
||||
sub = layout.column(align=True)
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Start")
|
||||
split.prop(strip, "frame_start", text=smpte_from_frame(frame_start))
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Duration")
|
||||
split.prop(strip, "frame_final_duration", text=smpte_from_frame(frame_final_duration))
|
||||
|
||||
# Use label, editing this value from the UI allows negative values,
|
||||
# users can adjust duration.
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split = split.split(factor=factor + 0.3 + max_factor, align=True)
|
||||
split.label(text="{:>14s}".format(smpte_from_frame(frame_final_end)), translate=False)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text=str(frame_final_end) + " ")
|
||||
|
||||
if not is_effect:
|
||||
|
||||
layout.alignment = 'RIGHT'
|
||||
sub = layout.column(align=True)
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Strip Offset Start")
|
||||
split.prop(strip, "frame_offset_start", text=smpte_from_frame(frame_offset_start))
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split.prop(strip, "frame_offset_end", text=smpte_from_frame(frame_offset_end))
|
||||
|
||||
layout.alignment = 'RIGHT'
|
||||
sub = layout.column(align=True)
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Hold Offset Start")
|
||||
split.prop(strip, "animation_offset_start", text=smpte_from_frame(strip.animation_offset_start))
|
||||
|
||||
split = sub.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split.prop(strip, "animation_offset_end", text=smpte_from_frame(strip.animation_offset_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 >= frame_final_start) and
|
||||
(frame_current <= frame_final_start + frame_final_duration)
|
||||
)
|
||||
|
||||
split = col.split(factor=factor + max_factor, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Current Frame")
|
||||
split = split.split(factor=factor + 0.3 + max_factor, align=True)
|
||||
frame_display = frame_current - frame_final_start
|
||||
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="Original Frame Range")
|
||||
split.alignment = 'LEFT'
|
||||
split.label(text="{:d}-{:d} ({:d})".format(sta, end, end - sta + 1), translate=False)
|
||||
|
||||
|
||||
class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Sound"
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
strip = context.active_strip
|
||||
if not strip:
|
||||
return False
|
||||
|
||||
return strip.type == 'SOUND'
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
st = context.space_data
|
||||
overlay_settings = st.timeline_overlay
|
||||
strip = context.active_strip
|
||||
sound = strip.sound
|
||||
|
||||
layout.active = not strip.mute
|
||||
|
||||
if sound is not None:
|
||||
layout.use_property_split = True
|
||||
col = layout.column()
|
||||
|
||||
split = col.split(factor=0.4)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Volume", text_ctxt=i18n_contexts.id_sound)
|
||||
split.prop(strip, "volume", text="")
|
||||
|
||||
layout.use_property_split = False
|
||||
col = layout.column()
|
||||
|
||||
split = col.split(factor=0.4)
|
||||
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=0.4)
|
||||
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=0.4)
|
||||
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=0.4)
|
||||
split.label(text="")
|
||||
split.prop(strip, "pitch_correction")
|
||||
|
||||
if overlay_settings.waveform_display_type == 'DEFAULT_WAVEFORMS':
|
||||
split = col.split(factor=0.4)
|
||||
split.label(text="")
|
||||
split.prop(strip, "show_waveform")
|
||||
|
||||
|
||||
class SEQUENCER_PT_adjust_comp(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Compositing"
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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 SEQUENCER_PT_adjust_transform(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Transform"
|
||||
bl_category = "Strip"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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")
|
||||
|
||||
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 SEQUENCER_PT_adjust_video(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Video"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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',
|
||||
'WIPE', 'GLOW', 'COLOR', 'MULTICAM', 'SPEED', 'ADJUSTMENT', 'COLORMIX',
|
||||
}
|
||||
|
||||
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 SEQUENCER_PT_adjust_color(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Color"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Strip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not cls.has_sequencer(context):
|
||||
return False
|
||||
|
||||
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',
|
||||
'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 SEQUENCER_PT_cache_settings(SequencerButtonsPanel, Panel):
|
||||
bl_label = "Cache Settings"
|
||||
bl_category = "Cache"
|
||||
@@ -2993,29 +1976,6 @@ class SEQUENCER_PT_view_safe_areas_center_cut(SequencerButtonsPanel_Output, Pane
|
||||
col.prop(safe_data, "action_center", slider=True)
|
||||
|
||||
|
||||
class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
bl_category = "Modifiers"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
strip = context.active_strip
|
||||
if strip.type == 'SOUND':
|
||||
sound = strip.sound
|
||||
else:
|
||||
sound = None
|
||||
|
||||
if sound is None:
|
||||
layout.prop(strip, "use_linear_modifiers", text="Linear Modifiers")
|
||||
|
||||
layout.operator("wm.call_menu", text="Add Modifier", icon='ADD').name = "SEQUENCER_MT_modifier_add"
|
||||
|
||||
layout.template_strip_modifiers()
|
||||
|
||||
|
||||
class SEQUENCER_PT_annotation(AnnotationDataPanel, SequencerButtonsPanel_Output, Panel):
|
||||
bl_space_type = 'SEQUENCE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
@@ -3184,10 +2144,7 @@ classes = (
|
||||
SEQUENCER_MT_preview_view_pie,
|
||||
SEQUENCER_MT_modifier_add,
|
||||
|
||||
SEQUENCER_PT_color_tag_picker,
|
||||
|
||||
SEQUENCER_PT_active_tool,
|
||||
SEQUENCER_PT_strip,
|
||||
|
||||
SEQUENCER_PT_gizmo_display,
|
||||
SEQUENCER_PT_overlay,
|
||||
@@ -3196,36 +2153,12 @@ classes = (
|
||||
SEQUENCER_PT_sequencer_overlay_strips,
|
||||
SEQUENCER_PT_sequencer_overlay_waveforms,
|
||||
|
||||
SEQUENCER_PT_effect,
|
||||
SEQUENCER_PT_scene,
|
||||
SEQUENCER_PT_scene_sound,
|
||||
SEQUENCER_PT_mask,
|
||||
SEQUENCER_PT_effect_text_style,
|
||||
SEQUENCER_PT_effect_text_outline,
|
||||
SEQUENCER_PT_effect_text_shadow,
|
||||
SEQUENCER_PT_effect_text_box,
|
||||
SEQUENCER_PT_effect_text_layout,
|
||||
SEQUENCER_PT_movie_clip,
|
||||
|
||||
SEQUENCER_PT_adjust_comp,
|
||||
SEQUENCER_PT_adjust_transform,
|
||||
SEQUENCER_PT_adjust_crop,
|
||||
SEQUENCER_PT_adjust_video,
|
||||
SEQUENCER_PT_adjust_color,
|
||||
SEQUENCER_PT_adjust_sound,
|
||||
|
||||
SEQUENCER_PT_time,
|
||||
SEQUENCER_PT_source,
|
||||
|
||||
SEQUENCER_PT_modifiers,
|
||||
|
||||
SEQUENCER_PT_cache_settings,
|
||||
SEQUENCER_PT_cache_view_settings,
|
||||
SEQUENCER_PT_proxy_settings,
|
||||
SEQUENCER_PT_strip_proxy,
|
||||
|
||||
SEQUENCER_PT_custom_props,
|
||||
|
||||
SEQUENCER_PT_view,
|
||||
SEQUENCER_PT_view_cursor,
|
||||
SEQUENCER_PT_frame_overlay,
|
||||
|
||||
@@ -347,6 +347,31 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat
|
||||
}
|
||||
}
|
||||
}
|
||||
/* For Video Editing template. */
|
||||
if (STRPREFIX(workspace->id.name + 2, "Video Editing")) {
|
||||
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
|
||||
bScreen *screen = layout->screen;
|
||||
if (screen) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_SEQ) {
|
||||
if (((SpaceSeq *)sl)->view == SEQ_VIEW_PREVIEW) {
|
||||
continue;
|
||||
}
|
||||
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
|
||||
&sl->regionbase;
|
||||
ARegion *sidebar = BKE_region_find_in_listbase_by_type(regionbase, RGN_TYPE_UI);
|
||||
sidebar->flag |= RGN_FLAG_HIDDEN;
|
||||
}
|
||||
if (sl->spacetype == SPACE_PROPERTIES) {
|
||||
SpaceProperties *properties = reinterpret_cast<SpaceProperties *>(sl);
|
||||
properties->mainb = properties->mainbo = properties->mainbuser = BCONTEXT_STRIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blo_update_defaults_paint(Paint *paint)
|
||||
|
||||
@@ -33,6 +33,7 @@ set(LIB
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
PRIVATE bf::nodes
|
||||
PRIVATE bf::windowmanager
|
||||
PRIVATE bf::sequencer
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
@@ -38,6 +39,9 @@
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "SEQ_modifier.hh"
|
||||
#include "SEQ_select.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
@@ -523,6 +527,46 @@ static bool buttons_context_path_texture(const bContext *C,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool buttons_context_path_strip(ButsContextPath *path)
|
||||
{
|
||||
PointerRNA *ptr = &path->ptr[path->len - 1];
|
||||
/* If we already have a (pinned) strip, we're done. */
|
||||
if (RNA_struct_is_a(ptr->type, &RNA_Strip)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buttons_context_path_scene(path)) {
|
||||
Scene *scene = static_cast<Scene *>(path->ptr[path->len - 1].data);
|
||||
Strip *active_strip = blender::seq::select_active_get(scene);
|
||||
if (active_strip == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
path->ptr[path->len] = RNA_pointer_create_discrete(&scene->id, &RNA_Strip, active_strip);
|
||||
path->len++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool buttons_context_path_strip_modifier(Scene *sequencer_scene, ButsContextPath *path)
|
||||
{
|
||||
if (sequencer_scene && buttons_context_path_strip(path)) {
|
||||
Strip *active_strip = static_cast<Strip *>(path->ptr[path->len - 1].data);
|
||||
|
||||
StripModifierData *smd = blender::seq::modifier_get_active(active_strip);
|
||||
if (smd) {
|
||||
path->ptr[path->len] = RNA_pointer_create_discrete(
|
||||
&sequencer_scene->id, &RNA_StripModifier, smd);
|
||||
path->len++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WITH_FREESTYLE
|
||||
static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *view_layer)
|
||||
{
|
||||
@@ -554,6 +598,8 @@ static bool buttons_context_path(
|
||||
* Otherwise there is a loop reading the context that we are setting. */
|
||||
wmWindow *window = CTX_wm_window(C);
|
||||
Scene *scene = WM_window_get_active_scene(window);
|
||||
WorkSpace *workspace = WM_window_get_active_workspace(window);
|
||||
Scene *sequencer_scene = workspace->sequencer_scene;
|
||||
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
|
||||
|
||||
*path = {};
|
||||
@@ -568,7 +614,13 @@ static bool buttons_context_path(
|
||||
}
|
||||
/* No pinned root, use scene as initial root. */
|
||||
else if (mainb != BCONTEXT_TOOL) {
|
||||
path->ptr[0] = RNA_id_pointer_create(&scene->id);
|
||||
if (ELEM(mainb, BCONTEXT_STRIP, BCONTEXT_STRIP_MODIFIER)) {
|
||||
path->ptr[0] = RNA_id_pointer_create(&sequencer_scene->id);
|
||||
}
|
||||
else {
|
||||
path->ptr[0] = RNA_id_pointer_create(&scene->id);
|
||||
}
|
||||
|
||||
path->len++;
|
||||
|
||||
if (!ELEM(mainb,
|
||||
@@ -576,7 +628,9 @@ static bool buttons_context_path(
|
||||
BCONTEXT_RENDER,
|
||||
BCONTEXT_OUTPUT,
|
||||
BCONTEXT_VIEW_LAYER,
|
||||
BCONTEXT_WORLD))
|
||||
BCONTEXT_WORLD,
|
||||
BCONTEXT_STRIP,
|
||||
BCONTEXT_STRIP_MODIFIER))
|
||||
{
|
||||
path->ptr[path->len] = RNA_pointer_create_discrete(nullptr, &RNA_ViewLayer, view_layer);
|
||||
path->len++;
|
||||
@@ -645,6 +699,12 @@ static bool buttons_context_path(
|
||||
case BCONTEXT_BONE_CONSTRAINT:
|
||||
found = buttons_context_path_pose_bone(path);
|
||||
break;
|
||||
case BCONTEXT_STRIP:
|
||||
found = buttons_context_path_strip(path);
|
||||
break;
|
||||
case BCONTEXT_STRIP_MODIFIER:
|
||||
found = buttons_context_path_strip_modifier(sequencer_scene, path);
|
||||
break;
|
||||
default:
|
||||
found = false;
|
||||
break;
|
||||
@@ -851,6 +911,8 @@ const char *buttons_context_dir[] = {
|
||||
"curves",
|
||||
"pointcloud",
|
||||
"volume",
|
||||
"strip",
|
||||
"strip_modifier",
|
||||
nullptr,
|
||||
};
|
||||
|
||||
@@ -1173,6 +1235,14 @@ int /*eContextResult*/ buttons_context(const bContext *C,
|
||||
set_pointer_type(path, result, &RNA_GreasePencil);
|
||||
return CTX_RESULT_OK;
|
||||
}
|
||||
if (CTX_data_equals(member, "strip")) {
|
||||
set_pointer_type(path, result, &RNA_Strip);
|
||||
return CTX_RESULT_OK;
|
||||
}
|
||||
if (CTX_data_equals(member, "strip_modifier")) {
|
||||
set_pointer_type(path, result, &RNA_StripModifier);
|
||||
return CTX_RESULT_OK;
|
||||
}
|
||||
return CTX_RESULT_MEMBER_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -1206,7 +1276,9 @@ static void buttons_panel_context_draw(const bContext *C, Panel *panel)
|
||||
BCONTEXT_OUTPUT,
|
||||
BCONTEXT_SCENE,
|
||||
BCONTEXT_VIEW_LAYER,
|
||||
BCONTEXT_WORLD) &&
|
||||
BCONTEXT_WORLD,
|
||||
BCONTEXT_STRIP,
|
||||
BCONTEXT_STRIP_MODIFIER) &&
|
||||
ptr->type == &RNA_Scene)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_view2d_types.h"
|
||||
|
||||
@@ -43,6 +44,8 @@
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "SEQ_modifier.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_interface_c.hh"
|
||||
#include "UI_interface_layout.hh"
|
||||
@@ -177,24 +180,16 @@ void ED_buttons_visible_tabs_menu(bContext *C, uiLayout *layout, void * /*arg*/)
|
||||
|
||||
/* These can be reordered freely. */
|
||||
constexpr std::array<blender::StringRefNull, BCONTEXT_TOT> filter_items = {
|
||||
"show_properties_tool",
|
||||
"show_properties_render",
|
||||
"show_properties_output",
|
||||
"show_properties_view_layer",
|
||||
"show_properties_scene",
|
||||
"show_properties_world",
|
||||
"show_properties_collection",
|
||||
"show_properties_object",
|
||||
"show_properties_modifiers",
|
||||
"show_properties_effects",
|
||||
"show_properties_particles",
|
||||
"show_properties_physics",
|
||||
"show_properties_constraints",
|
||||
"show_properties_data",
|
||||
"show_properties_bone",
|
||||
"show_properties_bone_constraints",
|
||||
"show_properties_material",
|
||||
"show_properties_texture",
|
||||
"show_properties_tool", "show_properties_render",
|
||||
"show_properties_output", "show_properties_view_layer",
|
||||
"show_properties_scene", "show_properties_world",
|
||||
"show_properties_collection", "show_properties_object",
|
||||
"show_properties_modifiers", "show_properties_effects",
|
||||
"show_properties_particles", "show_properties_physics",
|
||||
"show_properties_constraints", "show_properties_data",
|
||||
"show_properties_bone", "show_properties_bone_constraints",
|
||||
"show_properties_material", "show_properties_texture",
|
||||
"show_properties_strip", "show_properties_strip_modifier",
|
||||
};
|
||||
|
||||
for (blender::StringRefNull item : filter_items) {
|
||||
@@ -258,6 +253,11 @@ blender::Vector<eSpaceButtons_Context> ED_buttons_tabs_list(const SpacePropertie
|
||||
|
||||
add_tab(BCONTEXT_TEXTURE);
|
||||
|
||||
add_spacer();
|
||||
|
||||
add_tab(BCONTEXT_STRIP);
|
||||
add_tab(BCONTEXT_STRIP_MODIFIER);
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
@@ -300,6 +300,10 @@ static const char *buttons_main_region_context_string(const short mainb)
|
||||
return "bone_constraint";
|
||||
case BCONTEXT_TOOL:
|
||||
return "tool";
|
||||
case BCONTEXT_STRIP:
|
||||
return "strip";
|
||||
case BCONTEXT_STRIP_MODIFIER:
|
||||
return "strip_modifier";
|
||||
}
|
||||
|
||||
/* All the cases should be handled. */
|
||||
@@ -766,6 +770,9 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
|
||||
break;
|
||||
case ND_RENDER_RESULT:
|
||||
break;
|
||||
case ND_SEQUENCER:
|
||||
ED_area_tag_redraw(area);
|
||||
break;
|
||||
case ND_MODE:
|
||||
case ND_LAYER:
|
||||
default:
|
||||
@@ -1129,6 +1136,14 @@ void ED_spacetype_buttons()
|
||||
fxti->panel_register(art);
|
||||
}
|
||||
}
|
||||
/* Register the panel types from strip modifiers. The actual panels are built per strip modifier
|
||||
* rather than per modifier type. */
|
||||
for (int i = 0; i < NUM_STRIP_MODIFIER_TYPES; i++) {
|
||||
const blender::seq::StripModifierTypeInfo *mti = blender::seq::modifier_type_info_get(i);
|
||||
if (mti != nullptr && mti->panel_register != nullptr) {
|
||||
mti->panel_register(art);
|
||||
}
|
||||
}
|
||||
|
||||
/* regions: header */
|
||||
art = MEM_callocN<ARegionType>("spacetype buttons region");
|
||||
|
||||
@@ -1036,7 +1036,6 @@ static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *region)
|
||||
wm->runtime->defaultconf, "Video Sequence Editor", SPACE_SEQ, RGN_TYPE_WINDOW);
|
||||
WM_event_add_keymap_handler_v2d_mask(®ion->runtime->handlers, keymap);
|
||||
|
||||
UI_panel_category_active_set_default(region, "Strip");
|
||||
ED_region_panels_init(wm, region);
|
||||
}
|
||||
|
||||
@@ -1213,15 +1212,6 @@ void ED_spacetype_sequencer()
|
||||
art->draw = sequencer_buttons_region_draw;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
/* Register the panel types from strip modifiers. The actual panels are built per strip modifier
|
||||
* rather than per modifier type. */
|
||||
for (int i = 0; i < NUM_STRIP_MODIFIER_TYPES; i++) {
|
||||
const seq::StripModifierTypeInfo *mti = seq::modifier_type_info_get(i);
|
||||
if (mti != nullptr && mti->panel_register != nullptr) {
|
||||
mti->panel_register(art);
|
||||
}
|
||||
}
|
||||
|
||||
sequencer_buttons_register(art);
|
||||
/* Toolbar. */
|
||||
art = MEM_callocN<ARegionType>("spacetype sequencer tools region");
|
||||
|
||||
@@ -108,6 +108,8 @@ typedef enum eSpaceButtons_Context {
|
||||
BCONTEXT_SHADERFX = 15,
|
||||
BCONTEXT_OUTPUT = 16,
|
||||
BCONTEXT_COLLECTION = 17,
|
||||
BCONTEXT_STRIP = 18,
|
||||
BCONTEXT_STRIP_MODIFIER = 19,
|
||||
|
||||
/* Keep last. */
|
||||
BCONTEXT_TOT,
|
||||
|
||||
@@ -2290,6 +2290,7 @@ static void rna_def_strip(BlenderRNA *brna)
|
||||
RNA_def_struct_ui_text(srna, "Strip", "Sequence strip in the sequence editor");
|
||||
RNA_def_struct_refine_func(srna, "rna_Strip_refine");
|
||||
RNA_def_struct_path_func(srna, "rna_Strip_path");
|
||||
RNA_def_struct_ui_icon(srna, ICON_SEQ_SEQUENCER);
|
||||
RNA_def_struct_idprops_func(srna, "rna_Strip_idprops");
|
||||
RNA_def_struct_system_idprops_func(srna, "rna_Strip_system_idprops");
|
||||
|
||||
|
||||
@@ -535,6 +535,12 @@ const EnumPropertyItem buttons_context_items[] = {
|
||||
{BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle Properties"},
|
||||
{BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics Properties"},
|
||||
{BCONTEXT_SHADERFX, "SHADERFX", ICON_SHADERFX, "Effects", "Visual Effects Properties"},
|
||||
{BCONTEXT_STRIP, "STRIP", ICON_SEQ_SEQUENCER, "Strip", "Strip Properties"},
|
||||
{BCONTEXT_STRIP_MODIFIER,
|
||||
"STRIP_MODIFIER",
|
||||
ICON_SEQ_STRIP_MODIFIER,
|
||||
"Strip Modifiers",
|
||||
"Strip Modifier Properties"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
@@ -5816,6 +5822,8 @@ static void rna_def_space_properties_filter(StructRNA *srna)
|
||||
"show_properties_particles",
|
||||
"show_properties_physics",
|
||||
"show_properties_effects",
|
||||
"show_properties_strip",
|
||||
"show_properties_strip_modifier",
|
||||
};
|
||||
|
||||
for (const int i : blender::IndexRange(BCONTEXT_TOT)) {
|
||||
|
||||
@@ -183,12 +183,6 @@ bool modifier_ui_poll(const bContext *C, PanelType * /*pt*/)
|
||||
if (!sequencer_scene) {
|
||||
return false;
|
||||
}
|
||||
if (const SpaceSeq *sseq = CTX_wm_space_seq(C)) {
|
||||
/* Only show modifiers in the sequencer view types, not the preview. */
|
||||
if (sseq->view == SEQ_VIEW_PREVIEW) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Strip *active_strip = seq::select_active_get(sequencer_scene);
|
||||
return active_strip != nullptr;
|
||||
}
|
||||
@@ -232,9 +226,9 @@ PanelType *modifier_panel_register(ARegionType *region_type,
|
||||
|
||||
modifier_type_panel_id(type, panel_type->idname);
|
||||
STRNCPY_UTF8(panel_type->label, "");
|
||||
STRNCPY_UTF8(panel_type->category, "Modifiers");
|
||||
STRNCPY_UTF8(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
|
||||
STRNCPY_UTF8(panel_type->active_property, "is_active");
|
||||
STRNCPY_UTF8(panel_type->context, "strip_modifier");
|
||||
|
||||
panel_type->draw_header = modifier_panel_header;
|
||||
panel_type->draw = draw;
|
||||
|
||||
Reference in New Issue
Block a user