2023-08-16 00:20:26 +10:00
|
|
|
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
2023-06-15 13:09:04 +10:00
|
|
|
#
|
2022-02-11 09:07:11 +11:00
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
2023-06-15 13:09:04 +10:00
|
|
|
|
2009-08-13 16:59:52 +00:00
|
|
|
import bpy
|
2020-09-17 14:38:45 +10:00
|
|
|
from bpy.types import Menu, Panel
|
2022-08-22 14:30:32 +02:00
|
|
|
from bpy.app.translations import contexts as i18n_contexts
|
2009-08-13 16:59:52 +00:00
|
|
|
|
2009-10-31 23:35:56 +00:00
|
|
|
|
2025-06-19 15:54:53 +02:00
|
|
|
def playback_controls(layout, context):
|
|
|
|
|
scene = context.scene
|
|
|
|
|
tool_settings = context.tool_settings
|
|
|
|
|
screen = context.screen
|
|
|
|
|
|
|
|
|
|
row = layout.row(align=True)
|
|
|
|
|
row.popover(
|
|
|
|
|
panel="TIME_PT_playback",
|
|
|
|
|
text="Playback",
|
|
|
|
|
)
|
|
|
|
|
row.popover(
|
|
|
|
|
panel="TIME_PT_keyframing_settings",
|
|
|
|
|
text="Keying",
|
|
|
|
|
text_ctxt=i18n_contexts.id_windowmanager,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
layout.separator_spacer()
|
|
|
|
|
|
|
|
|
|
row = layout.row(align=True)
|
|
|
|
|
row.prop(tool_settings, "use_keyframe_insert_auto", text="", toggle=True)
|
|
|
|
|
sub = row.row(align=True)
|
|
|
|
|
sub.active = tool_settings.use_keyframe_insert_auto
|
|
|
|
|
sub.popover(
|
|
|
|
|
panel="TIME_PT_auto_keyframing",
|
|
|
|
|
text="",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
row = layout.row(align=True)
|
|
|
|
|
row.operator("screen.frame_jump", text="", icon='REW').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':
|
2019-08-27 12:52:36 +02:00
|
|
|
row.scale_x = 2
|
2025-06-19 15:54:53 +02:00
|
|
|
row.operator("screen.animation_play", text="", icon='PLAY')
|
2019-08-27 12:52:36 +02:00
|
|
|
row.scale_x = 1
|
2025-06-19 15:54:53 +02:00
|
|
|
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
|
|
|
|
|
|
2025-06-27 12:42:00 +02:00
|
|
|
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
|
2025-06-19 15:54:53 +02:00
|
|
|
row.operator("screen.frame_jump", text="", icon='FF').end = True
|
2018-05-10 19:04:14 +02:00
|
|
|
|
2025-06-19 15:54:53 +02:00
|
|
|
layout.separator_spacer()
|
2018-05-10 19:04:14 +02:00
|
|
|
|
2025-06-19 15:54:53 +02:00
|
|
|
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")
|
2009-08-13 22:10:50 +00:00
|
|
|
|
2009-10-31 23:35:56 +00:00
|
|
|
|
2014-01-27 18:38:53 +11:00
|
|
|
class TIME_MT_editor_menus(Menu):
|
|
|
|
|
bl_idname = "TIME_MT_editor_menus"
|
|
|
|
|
bl_label = ""
|
|
|
|
|
|
2019-12-12 13:43:37 +11:00
|
|
|
def draw(self, context):
|
2018-12-20 12:02:21 +11:00
|
|
|
layout = self.layout
|
2018-12-20 13:46:56 +11:00
|
|
|
horizontal = (layout.direction == 'VERTICAL')
|
2019-12-12 13:43:37 +11:00
|
|
|
st = context.space_data
|
2018-08-15 15:54:58 +02:00
|
|
|
if horizontal:
|
|
|
|
|
row = layout.row()
|
|
|
|
|
sub = row.row(align=True)
|
|
|
|
|
else:
|
|
|
|
|
sub = layout
|
|
|
|
|
|
2018-07-02 20:25:59 +02:00
|
|
|
sub.menu("TIME_MT_view")
|
2019-11-30 17:03:22 +11:00
|
|
|
if st.show_markers:
|
|
|
|
|
sub.menu("TIME_MT_marker")
|
2014-01-27 18:38:53 +11:00
|
|
|
|
|
|
|
|
|
2011-11-11 03:28:46 +00:00
|
|
|
class TIME_MT_marker(Menu):
|
2011-11-03 12:47:39 +00:00
|
|
|
bl_label = "Marker"
|
|
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
|
2019-03-13 11:52:54 +11:00
|
|
|
marker_menu_generic(layout, context)
|
2011-11-03 12:47:39 +00:00
|
|
|
|
|
|
|
|
|
2011-08-12 06:57:00 +00:00
|
|
|
class TIME_MT_view(Menu):
|
2009-10-31 19:31:45 +00:00
|
|
|
bl_label = "View"
|
|
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
|
2014-04-26 03:36:34 +12:00
|
|
|
scene = context.scene
|
2009-10-31 19:31:45 +00:00
|
|
|
st = context.space_data
|
|
|
|
|
|
2024-01-23 12:11:22 +01:00
|
|
|
layout.prop(st, "show_region_hud")
|
2024-02-05 12:13:31 +01:00
|
|
|
layout.prop(st, "show_region_channels")
|
2022-09-20 14:36:20 +02:00
|
|
|
layout.separator()
|
|
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
# NOTE: "action" now, since timeline is in the dopesheet editor, instead of as own editor
|
|
|
|
|
layout.operator("action.view_all")
|
2024-05-30 17:19:10 +02:00
|
|
|
if context.scene.use_preview_range:
|
|
|
|
|
layout.operator("anim.scene_range_frame", text="Frame Preview Range")
|
|
|
|
|
else:
|
|
|
|
|
layout.operator("anim.scene_range_frame", text="Frame Scene Range")
|
2024-01-23 12:11:22 +01:00
|
|
|
layout.operator("action.view_frame")
|
2009-11-23 00:27:30 +00:00
|
|
|
layout.separator()
|
2009-10-31 19:31:45 +00:00
|
|
|
|
2024-01-23 12:11:22 +01:00
|
|
|
layout.prop(st, "show_markers")
|
|
|
|
|
layout.prop(st, "show_seconds")
|
|
|
|
|
layout.prop(st, "show_locked_time")
|
2019-11-30 17:03:22 +11:00
|
|
|
layout.separator()
|
|
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
layout.prop(scene, "show_keys_from_selected_only")
|
2024-01-23 12:11:22 +01:00
|
|
|
layout.prop(st.dopesheet, "show_only_errors")
|
2009-12-16 19:49:33 +00:00
|
|
|
layout.separator()
|
|
|
|
|
|
2025-06-27 12:23:48 +02:00
|
|
|
layout.menu("DOPESHEET_MT_cache")
|
2016-04-17 03:44:10 +12:00
|
|
|
layout.separator()
|
|
|
|
|
|
2024-01-23 12:11:22 +01:00
|
|
|
layout.menu("INFO_MT_area")
|
2012-11-04 18:26:30 +00:00
|
|
|
|
2010-07-05 22:22:22 +00:00
|
|
|
|
2019-03-13 11:52:54 +11:00
|
|
|
def marker_menu_generic(layout, context):
|
2011-11-03 12:47:39 +00:00
|
|
|
|
2015-09-01 03:51:50 +10:00
|
|
|
# layout.operator_context = 'EXEC_REGION_WIN'
|
2011-11-03 12:47:39 +00:00
|
|
|
|
|
|
|
|
layout.column()
|
|
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
tool_settings = context.tool_settings
|
|
|
|
|
layout.prop(tool_settings, "lock_markers")
|
2011-11-03 12:47:39 +00:00
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
layout.separator()
|
|
|
|
|
|
|
|
|
|
layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False
|
|
|
|
|
layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True
|
2011-11-03 12:47:39 +00:00
|
|
|
|
|
|
|
|
layout.separator()
|
|
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
layout.operator("marker.camera_bind")
|
2013-11-20 03:38:18 +11:00
|
|
|
|
2013-10-21 15:00:22 +00:00
|
|
|
layout.separator()
|
2013-11-20 03:38:18 +11:00
|
|
|
|
2024-03-14 10:38:16 +11:00
|
|
|
layout.menu("NLA_MT_marker_select")
|
2022-04-14 11:30:12 +02:00
|
|
|
|
|
|
|
|
layout.separator()
|
|
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
layout.operator("marker.move", text="Move Marker")
|
|
|
|
|
props = layout.operator("wm.call_panel", text="Rename Marker")
|
|
|
|
|
props.name = "TOPBAR_PT_name_marker"
|
|
|
|
|
props.keep_open = False
|
2018-04-24 17:59:32 +02:00
|
|
|
|
|
|
|
|
layout.separator()
|
|
|
|
|
|
2023-08-31 20:25:35 +02:00
|
|
|
layout.operator("marker.delete", text="Delete Marker")
|
|
|
|
|
|
|
|
|
|
if len(bpy.data.scenes) > 10:
|
|
|
|
|
layout.operator_context = 'INVOKE_DEFAULT'
|
|
|
|
|
layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY')
|
|
|
|
|
else:
|
|
|
|
|
layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene")
|
|
|
|
|
|
|
|
|
|
layout.operator("marker.duplicate", text="Duplicate Marker")
|
|
|
|
|
layout.operator("marker.add", text="Add Marker")
|
2011-11-03 12:47:39 +00:00
|
|
|
|
2015-04-14 12:11:24 +02:00
|
|
|
|
2018-05-10 18:33:41 +02:00
|
|
|
###################################
|
|
|
|
|
|
2018-06-05 16:35:20 +02:00
|
|
|
|
2018-05-10 18:33:41 +02:00
|
|
|
class TimelinePanelButtons:
|
|
|
|
|
bl_space_type = 'DOPESHEET_EDITOR'
|
|
|
|
|
bl_region_type = 'UI'
|
|
|
|
|
|
|
|
|
|
|
2018-05-10 19:28:27 +02:00
|
|
|
class TIME_PT_playback(TimelinePanelButtons, Panel):
|
|
|
|
|
bl_label = "Playback"
|
|
|
|
|
bl_region_type = 'HEADER'
|
2024-03-14 17:10:34 +01:00
|
|
|
bl_ui_units_x = 13
|
2018-05-10 19:28:27 +02:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
2020-09-07 14:22:29 -05:00
|
|
|
layout.use_property_split = True
|
|
|
|
|
layout.use_property_decorate = False
|
2018-05-10 19:28:27 +02:00
|
|
|
|
|
|
|
|
screen = context.screen
|
|
|
|
|
scene = context.scene
|
|
|
|
|
|
2020-10-29 12:31:48 +01:00
|
|
|
layout.prop(scene, "sync_mode", text="Sync")
|
|
|
|
|
col = layout.column(heading="Audio")
|
2020-09-07 14:22:29 -05:00
|
|
|
col.prop(scene, "use_audio_scrub", text="Scrubbing")
|
2024-01-18 11:01:13 +11:00
|
|
|
col.prop(scene, "use_audio")
|
2020-09-07 14:22:29 -05:00
|
|
|
|
|
|
|
|
col = layout.column(heading="Playback")
|
|
|
|
|
col.prop(scene, "lock_frame_selection_to_range", text="Limit to Frame Range")
|
|
|
|
|
col.prop(screen, "use_follow", text="Follow Current Frame")
|
|
|
|
|
|
|
|
|
|
col = layout.column(heading="Play In")
|
|
|
|
|
col.prop(screen, "use_play_top_left_3d_editor", text="Active Editor")
|
|
|
|
|
col.prop(screen, "use_play_3d_editors", text="3D Viewport")
|
|
|
|
|
col.prop(screen, "use_play_animation_editors", text="Animation Editors")
|
|
|
|
|
col.prop(screen, "use_play_image_editors", text="Image Editor")
|
2024-04-05 18:17:41 +02:00
|
|
|
col.prop(screen, "use_play_properties_editors", text="Properties and Sidebars")
|
2020-09-07 14:22:29 -05:00
|
|
|
col.prop(screen, "use_play_clip_editors", text="Movie Clip Editor")
|
|
|
|
|
col.prop(screen, "use_play_node_editors", text="Node Editors")
|
|
|
|
|
col.prop(screen, "use_play_sequence_editors", text="Video Sequencer")
|
2023-05-24 09:25:10 +02:00
|
|
|
col.prop(screen, "use_play_spreadsheet_editors", text="Spreadsheet")
|
2020-09-07 14:22:29 -05:00
|
|
|
|
|
|
|
|
col = layout.column(heading="Show")
|
|
|
|
|
col.prop(scene, "show_subframe", text="Subframes")
|
2018-05-10 19:28:27 +02:00
|
|
|
|
|
|
|
|
layout.separator()
|
|
|
|
|
|
|
|
|
|
row = layout.row(align=True)
|
|
|
|
|
row.operator("anim.start_frame_set")
|
|
|
|
|
row.operator("anim.end_frame_set")
|
|
|
|
|
|
|
|
|
|
|
2018-05-10 18:33:41 +02:00
|
|
|
class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel):
|
|
|
|
|
bl_label = "Keyframing Settings"
|
|
|
|
|
bl_options = {'HIDE_HEADER'}
|
2018-05-25 17:02:40 +02:00
|
|
|
bl_region_type = 'HEADER'
|
2018-05-10 18:33:41 +02:00
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
|
|
|
|
|
scene = context.scene
|
2018-12-17 17:26:47 +11:00
|
|
|
tool_settings = context.tool_settings
|
2018-05-10 18:33:41 +02:00
|
|
|
|
|
|
|
|
col = layout.column(align=True)
|
2020-10-06 15:17:36 -05:00
|
|
|
col.label(text="Active Keying Set")
|
2018-05-10 18:33:41 +02:00
|
|
|
row = col.row(align=True)
|
|
|
|
|
row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="")
|
|
|
|
|
row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
|
|
|
|
|
row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT')
|
|
|
|
|
|
|
|
|
|
col = layout.column(align=True)
|
2020-10-06 15:17:36 -05:00
|
|
|
col.label(text="New Keyframe Type")
|
2018-12-17 17:26:47 +11:00
|
|
|
col.prop(tool_settings, "keyframe_type", text="")
|
2013-11-20 03:38:18 +11:00
|
|
|
|
2021-05-03 00:03:00 +03:00
|
|
|
layout.prop(tool_settings, "use_keyframe_cycle_aware")
|
|
|
|
|
|
2020-12-16 18:02:40 +11:00
|
|
|
|
2020-10-06 15:17:36 -05:00
|
|
|
class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
|
|
|
|
|
bl_label = "Auto Keyframing"
|
|
|
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
|
bl_region_type = 'HEADER'
|
|
|
|
|
bl_ui_units_x = 9
|
|
|
|
|
|
|
|
|
|
def draw(self, context):
|
|
|
|
|
layout = self.layout
|
|
|
|
|
|
|
|
|
|
tool_settings = context.tool_settings
|
|
|
|
|
prefs = context.preferences
|
|
|
|
|
|
|
|
|
|
layout.active = tool_settings.use_keyframe_insert_auto
|
|
|
|
|
|
|
|
|
|
layout.prop(tool_settings, "auto_keying_mode", expand=True)
|
|
|
|
|
|
2018-05-10 18:33:41 +02:00
|
|
|
col = layout.column(align=True)
|
2020-10-06 15:17:36 -05:00
|
|
|
col.prop(tool_settings, "use_keyframe_insert_keyingset", text="Only Active Keying Set", toggle=False)
|
2018-12-21 12:47:44 +11:00
|
|
|
if not prefs.edit.use_keyframe_insert_available:
|
2018-12-17 17:26:47 +11:00
|
|
|
col.prop(tool_settings, "use_record_with_nla", text="Layered Recording")
|
2018-05-10 18:33:41 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
###################################
|
2011-11-03 12:47:39 +00:00
|
|
|
|
2017-03-18 20:03:24 +11:00
|
|
|
classes = (
|
|
|
|
|
TIME_MT_editor_menus,
|
|
|
|
|
TIME_MT_marker,
|
|
|
|
|
TIME_MT_view,
|
2018-05-10 19:28:27 +02:00
|
|
|
TIME_PT_playback,
|
2018-05-10 18:33:41 +02:00
|
|
|
TIME_PT_keyframing_settings,
|
2020-10-06 15:17:36 -05:00
|
|
|
TIME_PT_auto_keyframing,
|
2017-03-18 20:03:24 +11:00
|
|
|
)
|
|
|
|
|
|
2011-04-04 10:13:04 +00:00
|
|
|
if __name__ == "__main__": # only for live edit.
|
2017-03-18 20:03:24 +11:00
|
|
|
from bpy.utils import register_class
|
|
|
|
|
for cls in classes:
|
|
|
|
|
register_class(cls)
|