Last active
July 28, 2020 14:15
-
-
Save tin2tin/2fda808d293f0aeaf48e0cb07bac21b4 to your computer and use it in GitHub Desktop.
Playback controls in Blender VSE header and Project Dimensions and Output settings in Sidebar Tabs, so you can get rid of the "Timeline" and "Properties" areas.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ##### BEGIN GPL LICENSE BLOCK ##### | |
# | |
# This program is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License | |
# as published by the Free Software Foundation; either version 2 | |
# of the License, or (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, write to the Free Software Foundation, | |
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
# | |
# ##### END GPL LICENSE BLOCK ##### | |
# <pep8 compliant> | |
bl_info = { | |
"name": "Playback Controls in VSE Header", | |
"author": "Tintwotin", | |
"version": (0, 1), | |
"blender": (2, 81, 0), | |
"location": "Sequence Editor > Header", | |
"description": "Adds timeline controls to the Sequencer header", | |
"warning": "", | |
"wiki_url": "", | |
"category": "Sequencer", | |
} | |
import bpy | |
from bpy.types import ( | |
Header, | |
Menu, | |
Panel, | |
UIList, | |
) | |
from bpy.app.translations import pgettext_tip as tip_ | |
from bl_ui.utils import PresetPanel | |
def menu_func(self, context): | |
layout = self.layout | |
scene = context.scene | |
screen = context.screen | |
userprefs = context.preferences | |
tool_settings = context.tool_settings | |
st = context.space_data | |
if not st.view_type in {'PREVIEW'}: | |
layout.separator_spacer() | |
layout.prop(tool_settings, "use_keyframe_insert_auto", text="", toggle=True) | |
row = layout.row(align=True) | |
row.operator("screen.frame_jump", text="", icon='PLAY_REVERSE').end = False | |
row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False | |
if not screen.is_animation_playing: | |
# if using JACK and A/V sync: | |
# hide the play-reversed button | |
# since JACK transport doesn't support reversed playback | |
if scene.sync_mode == 'AUDIO_SYNC' and context.preferences.system.audio_device == 'JACK': | |
row.scale_x = 2 | |
row.operator("screen.animation_play", text="", icon='PLAY') | |
row.scale_x = 1 | |
else: | |
row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True | |
row.operator("screen.animation_play", text="", icon='PLAY') | |
else: | |
row.scale_x = 2 | |
row.operator("screen.animation_play", text="", icon='PAUSE') | |
row.scale_x = 1 | |
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True | |
row.operator("screen.frame_jump", text="", icon='FF').end = True | |
layout.separator_spacer() | |
row = layout.row(align=True) | |
# row.prop(scene, "sync_mode", text="") | |
row.popover( | |
panel="TIME_PT_playback", | |
text="Playback", | |
) | |
# row.popover( | |
# panel="TIME_PT_keyframing_settings", | |
# text="Keying", | |
# ) | |
row = layout.row() | |
if scene.show_subframe: | |
row.scale_x = 1.15 | |
row.prop(scene, "frame_float", text="") | |
else: | |
row.scale_x = 0.95 | |
row.prop(scene, "frame_current", text="") | |
row = layout.row(align=True) | |
row.prop(scene, "use_preview_range", text="", toggle=True) | |
sub = row.row(align=True) | |
sub.scale_x = 0.8 | |
if not scene.use_preview_range: | |
sub.prop(scene, "frame_start", text="Start") | |
sub.prop(scene, "frame_end", text="End") | |
else: | |
sub.prop(scene, "frame_preview_start", text="Start") | |
sub.prop(scene, "frame_preview_end", text="End") | |
class SequencerButtonsPanel_dimentions: | |
bl_space_type = 'SEQUENCE_EDITOR' | |
bl_region_type = 'UI' | |
bl_category = "Project" | |
@staticmethod | |
def has_sequencer(context): | |
return (context.space_data.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}) | |
class SEQUENCER_PT_dimensions(SequencerButtonsPanel_dimentions, Panel): | |
bl_space_type = 'SEQUENCE_EDITOR' | |
bl_region_type = 'UI' | |
bl_label = "Dimensions" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
_frame_rate_args_prev = None | |
_preset_class = None | |
# def draw_header_preset(self, _context): | |
# SEQUENCER_PT_presets.draw_panel_header(self.layout) | |
@staticmethod | |
def _draw_framerate_label(*args): | |
# avoids re-creating text string each draw | |
if SEQUENCER_PT_dimensions._frame_rate_args_prev == args: | |
return SEQUENCER_PT_dimensions._frame_rate_ret | |
fps, fps_base, preset_label = args | |
if fps_base == 1.0: | |
fps_rate = round(fps) | |
else: | |
fps_rate = round(fps / fps_base, 2) | |
# TODO: Change the following to iterate over existing presets | |
custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60}) | |
if custom_framerate is True: | |
fps_label_text = tip_("Custom (%.4g fps)") % fps_rate | |
show_framerate = True | |
else: | |
fps_label_text = tip_("%.4g fps") % fps_rate | |
show_framerate = (preset_label == "Custom") | |
SEQUENCER_PT_dimensions._frame_rate_args_prev = args | |
SEQUENCER_PT_dimensions._frame_rate_ret = args = (fps_label_text, show_framerate) | |
return args | |
@staticmethod | |
def draw_framerate(layout, rd): | |
if SEQUENCER_PT_dimensions._preset_class is None: | |
SEQUENCER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets | |
args = rd.fps, rd.fps_base, SEQUENCER_PT_dimensions._preset_class.bl_label | |
fps_label_text, show_framerate = SEQUENCER_PT_dimensions._draw_framerate_label(*args) | |
layout.menu("RENDER_MT_framerate_presets", text=fps_label_text) | |
if show_framerate: | |
col = layout.column(align=True) | |
col.prop(rd, "fps") | |
col.prop(rd, "fps_base", text="Base") | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False # No animation. | |
scene = context.scene | |
rd = scene.render | |
col = layout.column(align=True) | |
col.prop(rd, "resolution_x", text="Resolution X") | |
col.prop(rd, "resolution_y", text="Y") | |
col.prop(rd, "resolution_percentage", text="%") | |
col = layout.column(align=True) | |
col.prop(rd, "pixel_aspect_x", text="Aspect X") | |
col.prop(rd, "pixel_aspect_y", text="Y") | |
col = layout.column(align=True) | |
col.prop(rd, "use_border") | |
sub = col.column(align=True) | |
sub.active = rd.use_border | |
sub.prop(rd, "use_crop_to_border") | |
col = layout.column(align=True) | |
col.prop(scene, "frame_start", text="Frame Start") | |
col.prop(scene, "frame_end", text="End") | |
col.prop(scene, "frame_step", text="Step") | |
col = layout.column(heading="Frame Rate") | |
self.draw_framerate(col, rd) | |
# Output | |
class SEQUENCER_PT_presets(PresetPanel, Panel): | |
bl_label = "Render Presets" | |
preset_subdir = "render" | |
preset_operator = "script.execute_preset" | |
preset_add_operator = "render.preset_add" | |
class SEQUENCER_PT_ffmpeg_presets(PresetPanel, Panel): | |
bl_label = "FFMPEG Presets" | |
preset_subdir = "ffmpeg" | |
preset_operator = "script.python_file_run" | |
class RENDER_MT_framerate_presets(Menu): | |
bl_label = "Frame Rate Presets" | |
preset_subdir = "framerate" | |
preset_operator = "script.execute_preset" | |
draw = Menu.draw_preset | |
class SEQUENCER_PT_dimensions(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Dimensions" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
_frame_rate_args_prev = None | |
_preset_class = None | |
def draw_header_preset(self, _context): | |
SEQUENCER_PT_presets.draw_panel_header(self.layout) | |
@staticmethod | |
def _draw_framerate_label(*args): | |
# avoids re-creating text string each draw | |
if SEQUENCER_PT_dimensions._frame_rate_args_prev == args: | |
return SEQUENCER_PT_dimensions._frame_rate_ret | |
fps, fps_base, preset_label = args | |
if fps_base == 1.0: | |
fps_rate = round(fps) | |
else: | |
fps_rate = round(fps / fps_base, 2) | |
# TODO: Change the following to iterate over existing presets | |
custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60}) | |
if custom_framerate is True: | |
fps_label_text = tip_("Custom (%.4g fps)") % fps_rate | |
show_framerate = True | |
else: | |
fps_label_text = tip_("%.4g fps") % fps_rate | |
show_framerate = (preset_label == "Custom") | |
SEQUENCER_PT_dimensions._frame_rate_args_prev = args | |
SEQUENCER_PT_dimensions._frame_rate_ret = args = (fps_label_text, show_framerate) | |
return args | |
@staticmethod | |
def draw_framerate(layout, rd): | |
if SEQUENCER_PT_dimensions._preset_class is None: | |
SEQUENCER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets | |
args = rd.fps, rd.fps_base, SEQUENCER_PT_dimensions._preset_class.bl_label | |
fps_label_text, show_framerate = SEQUENCER_PT_dimensions._draw_framerate_label(*args) | |
layout.menu("RENDER_MT_framerate_presets", text=fps_label_text) | |
if show_framerate: | |
col = layout.column(align=True) | |
col.prop(rd, "fps") | |
col.prop(rd, "fps_base", text="Base") | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False # No animation. | |
scene = context.scene | |
rd = scene.render | |
col = layout.column(align=True) | |
col.prop(rd, "resolution_x", text="Resolution X") | |
col.prop(rd, "resolution_y", text="Y") | |
col.prop(rd, "resolution_percentage", text="%") | |
col = layout.column(align=True) | |
col.prop(rd, "pixel_aspect_x", text="Aspect X") | |
col.prop(rd, "pixel_aspect_y", text="Y") | |
col = layout.column(align=True) | |
col.prop(rd, "use_border") | |
sub = col.column(align=True) | |
sub.active = rd.use_border | |
sub.prop(rd, "use_crop_to_border") | |
col = layout.column(align=True) | |
col.prop(scene, "frame_start", text="Frame Start") | |
col.prop(scene, "frame_end", text="End") | |
col.prop(scene, "frame_step", text="Step") | |
col = layout.column(heading="Frame Rate") | |
self.draw_framerate(col, rd) | |
class SEQUENCER_PT_frame_remapping(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Time Remapping" | |
bl_parent_id = "SEQUENCER_PT_dimensions" | |
bl_options = {'DEFAULT_CLOSED'} | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False # No animation. | |
rd = context.scene.render | |
col = layout.column(align=True) | |
col.prop(rd, "frame_map_old", text="Old") | |
col.prop(rd, "frame_map_new", text="New") | |
class SEQUENCER_PT_post_processing(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Post Processing" | |
bl_options = {'DEFAULT_CLOSED'} | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
rd = context.scene.render | |
col = layout.column(heading="Pipeline") | |
col.prop(rd, "use_compositing") | |
col.prop(rd, "use_sequencer") | |
layout.prop(rd, "dither_intensity", text="Dither", slider=True) | |
class SEQUENCER_PT_stamp(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Metadata" | |
bl_options = {'DEFAULT_CLOSED'} | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False # No animation. | |
rd = context.scene.render | |
if rd.use_sequencer: | |
layout.prop(rd, "metadata_input") | |
col = layout.column(heading="Include") | |
col.prop(rd, "use_stamp_date", text="Date") | |
col.prop(rd, "use_stamp_time", text="Time") | |
col.prop(rd, "use_stamp_render_time", text="Render Time") | |
col.prop(rd, "use_stamp_frame", text="Frame") | |
col.prop(rd, "use_stamp_frame_range", text="Frame Range") | |
col.prop(rd, "use_stamp_memory", text="Memory") | |
col.prop(rd, "use_stamp_hostname", text="Hostname") | |
col.prop(rd, "use_stamp_camera", text="Camera") | |
col.prop(rd, "use_stamp_lens", text="Lens") | |
col.prop(rd, "use_stamp_scene", text="Scene") | |
col.prop(rd, "use_stamp_marker", text="Marker") | |
col.prop(rd, "use_stamp_filename", text="Filename") | |
class SEQUENCER_PT_stamp_note(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Note" | |
bl_parent_id = "SEQUENCER_PT_stamp" | |
bl_options = {'DEFAULT_CLOSED'} | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw_header(self, context): | |
rd = context.scene.render | |
self.layout.prop(rd, "use_stamp_note", text="") | |
def draw(self, context): | |
layout = self.layout | |
rd = context.scene.render | |
layout.active = rd.use_stamp_note | |
layout.prop(rd, "stamp_note_text", text="") | |
class SEQUENCER_PT_stamp_burn(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Burn Into Image" | |
bl_parent_id = "SEQUENCER_PT_stamp" | |
bl_options = {'DEFAULT_CLOSED'} | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw_header(self, context): | |
rd = context.scene.render | |
self.layout.prop(rd, "use_stamp", text="") | |
def draw(self, context): | |
layout = self.layout | |
rd = context.scene.render | |
layout.use_property_split = True | |
col = layout.column() | |
col.active = rd.use_stamp | |
col.prop(rd, "stamp_font_size", text="Font Size") | |
col.column().prop(rd, "stamp_foreground", slider=True) | |
col.column().prop(rd, "stamp_background", slider=True) | |
col.prop(rd, "use_stamp_labels", text="Include Labels") | |
class SEQUENCER_PT_output(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Output" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = False | |
layout.use_property_decorate = False # No animation. | |
rd = context.scene.render | |
image_settings = rd.image_settings | |
layout.prop(rd, "filepath", text="") | |
layout.use_property_split = True | |
col = layout.column(heading="Saving") | |
col.prop(rd, "use_file_extension") | |
col.prop(rd, "use_render_cache") | |
layout.template_image_settings(image_settings, color_management=False) | |
if not rd.is_movie_format: | |
col = layout.column(heading="Image Sequence") | |
col.prop(rd, "use_overwrite") | |
col.prop(rd, "use_placeholder") | |
class SEQUENCER_PT_output_views(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Views" | |
bl_parent_id = "SEQUENCER_PT_output" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
@classmethod | |
def poll(cls, context): | |
rd = context.scene.render | |
return rd.use_multiview | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = False | |
layout.use_property_decorate = False # No animation. | |
rd = context.scene.render | |
layout.template_image_views(rd.image_settings) | |
class SEQUENCER_PT_encoding(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Encoding" | |
bl_parent_id = "SEQUENCER_PT_output" | |
bl_options = {'DEFAULT_CLOSED'} | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
def draw_header_preset(self, _context): | |
SEQUENCER_PT_ffmpeg_presets.draw_panel_header(self.layout) | |
@classmethod | |
def poll(cls, context): | |
rd = context.scene.render | |
return rd.image_settings.file_format in {'FFMPEG', 'XVID', 'H264', 'THEORA'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False | |
rd = context.scene.render | |
ffmpeg = rd.ffmpeg | |
layout.prop(rd.ffmpeg, "format") | |
layout.prop(ffmpeg, "use_autosplit") | |
class SEQUENCER_PT_encoding_video(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Video" | |
bl_parent_id = "SEQUENCER_PT_encoding" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
@classmethod | |
def poll(cls, context): | |
rd = context.scene.render | |
return rd.image_settings.file_format in {'FFMPEG', 'XVID', 'H264', 'THEORA'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False | |
self.draw_vcodec(context) | |
def draw_vcodec(self, context): | |
"""Video codec options.""" | |
layout = self.layout | |
ffmpeg = context.scene.render.ffmpeg | |
needs_codec = ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG', 'MPEG4', 'WEBM'} | |
if needs_codec: | |
layout.prop(ffmpeg, "codec") | |
if needs_codec and ffmpeg.codec == 'NONE': | |
return | |
if ffmpeg.codec == 'DNXHD': | |
layout.prop(ffmpeg, "use_lossless_output") | |
# Output quality | |
use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4', 'WEBM'} | |
if use_crf: | |
layout.prop(ffmpeg, "constant_rate_factor") | |
# Encoding speed | |
layout.prop(ffmpeg, "ffmpeg_preset") | |
# I-frames | |
layout.prop(ffmpeg, "gopsize") | |
# B-Frames | |
row = layout.row(align=True, heading="Max B-frames") | |
row.prop(ffmpeg, "use_max_b_frames", text="") | |
sub = row.row(align=True) | |
sub.active = ffmpeg.use_max_b_frames | |
sub.prop(ffmpeg, "max_b_frames", text="") | |
if not use_crf or ffmpeg.constant_rate_factor == 'NONE': | |
col = layout.column() | |
sub = col.column(align=True) | |
sub.prop(ffmpeg, "video_bitrate") | |
sub.prop(ffmpeg, "minrate", text="Minimum") | |
sub.prop(ffmpeg, "maxrate", text="Maximum") | |
col.prop(ffmpeg, "buffersize", text="Buffer") | |
col.separator() | |
col.prop(ffmpeg, "muxrate", text="Mux Rate") | |
col.prop(ffmpeg, "packetsize", text="Mux Packet Size") | |
class SEQUENCER_PT_encoding_audio(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Audio" | |
bl_parent_id = "SEQUENCER_PT_encoding" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
@classmethod | |
def poll(cls, context): | |
rd = context.scene.render | |
return rd.image_settings.file_format in {'FFMPEG', 'XVID', 'H264', 'THEORA'} | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
layout.use_property_decorate = False | |
rd = context.scene.render | |
ffmpeg = rd.ffmpeg | |
if ffmpeg.format != 'MP3': | |
layout.prop(ffmpeg, "audio_codec", text="Audio Codec") | |
if ffmpeg.audio_codec != 'NONE': | |
layout.prop(ffmpeg, "audio_channels") | |
layout.prop(ffmpeg, "audio_mixrate", text="Sample Rate") | |
layout.prop(ffmpeg, "audio_bitrate") | |
layout.prop(ffmpeg, "audio_volume", slider=True) | |
class RENDER_UL_renderviews(UIList): | |
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, index): | |
view = item | |
if self.layout_type in {'DEFAULT', 'COMPACT'}: | |
if view.name in {"left", "right"}: | |
layout.label(text=view.name, icon_value=icon + (not view.use)) | |
else: | |
layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False) | |
layout.prop(view, "use", text="", index=index) | |
elif self.layout_type == 'GRID': | |
layout.alignment = 'CENTER' | |
layout.label(text="", icon_value=icon + (not view.use)) | |
class SEQUENCER_PT_stereoscopy(SequencerButtonsPanel_dimentions, Panel): | |
bl_label = "Stereoscopy" | |
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} | |
bl_options = {'DEFAULT_CLOSED'} | |
def draw_header(self, context): | |
rd = context.scene.render | |
self.layout.prop(rd, "use_multiview", text="") | |
def draw(self, context): | |
layout = self.layout | |
scene = context.scene | |
rd = scene.render | |
rv = rd.views.active | |
layout.active = rd.use_multiview | |
basic_stereo = rd.views_format == 'STEREO_3D' | |
row = layout.row() | |
layout.row().prop(rd, "views_format", expand=True) | |
if basic_stereo: | |
row = layout.row() | |
row.template_list("RENDER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2) | |
row = layout.row() | |
row.use_property_split = True | |
row.use_property_decorate = False | |
row.prop(rv, "file_suffix") | |
else: | |
row = layout.row() | |
row.template_list("RENDER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2) | |
col = row.column(align=True) | |
col.operator("scene.render_view_add", icon='ADD', text="") | |
col.operator("scene.render_view_remove", icon='REMOVE', text="") | |
row = layout.row() | |
row.use_property_split = True | |
row.use_property_decorate = False | |
row.prop(rv, "camera_suffix") | |
classes = ( | |
SEQUENCER_PT_presets, | |
SEQUENCER_PT_ffmpeg_presets, | |
RENDER_MT_framerate_presets, | |
SEQUENCER_PT_dimensions, | |
SEQUENCER_PT_frame_remapping, | |
SEQUENCER_PT_stereoscopy, | |
SEQUENCER_PT_output, | |
SEQUENCER_PT_output_views, | |
SEQUENCER_PT_encoding, | |
SEQUENCER_PT_encoding_video, | |
SEQUENCER_PT_encoding_audio, | |
SEQUENCER_PT_stamp, | |
SEQUENCER_PT_stamp_note, | |
SEQUENCER_PT_stamp_burn, | |
RENDER_UL_renderviews, | |
SEQUENCER_PT_post_processing, | |
) | |
if __name__ == "__main__": # only for live edit. | |
from bpy.utils import register_class | |
for cls in classes: | |
register_class(cls) | |
def register(): | |
bpy.types.SEQUENCER_HT_header.append(menu_func) | |
def unregister(): | |
bpy.types.SEQUENCER_HT_header.remove(menu_func) | |
if __name__ == "__main__": | |
register() |
Author
tin2tin
commented
Jul 28, 2020
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment