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:
Richard Antalik
2025-10-03 17:33:17 +02:00
committed by Richard Antalik
parent 258f449783
commit f385327442
14 changed files with 1265 additions and 1106 deletions

View File

@@ -60,6 +60,8 @@ _modules = [
"properties_texture",
"properties_world",
"properties_collection",
"properties_strip",
"properties_strip_modifier",
"generic_ui_list",
# Generic Space Modules

View 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)

View 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)

View File

@@ -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)

View File

@@ -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,

View File

@@ -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)

View File

@@ -33,6 +33,7 @@ set(LIB
PRIVATE bf::intern::guardedalloc
PRIVATE bf::nodes
PRIVATE bf::windowmanager
PRIVATE bf::sequencer
)

View File

@@ -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;

View File

@@ -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");

View File

@@ -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(&region->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");

View File

@@ -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,

View File

@@ -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");

View File

@@ -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)) {

View File

@@ -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;