This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/release/scripts/startup/bl_ui/space_nla.py
RedMser 1f828a5a06 Animation: Add redo panel to Dopesheet and NLA
Add the Redo panel to the dopesheet & NLA editors. This also implicitly
adds it to the timeline editor, since it's a kind of action editor
internally.

This feature is needed for changing advanced properties of animation
operators, such as select grouped (see D14811). But it can also be
useful for existing operators, like precise keyframe position tweaking.

Changes are basically the same as in D6286 (which added the redo panel
for Graph Editor).

Some operators have internal properties that should be hidden. A full
list can be found in T98195. These will be fixed in a follow-up patch.

Reviewed By: sybren

Differential Revision: https://developer.blender.org/D14960
2022-09-20 14:37:16 +02:00

352 lines
10 KiB
Python

# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import Header, Menu, Panel
from bpy.app.translations import contexts as i18n_contexts
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
DopesheetActionPanelBase,
dopesheet_filter,
)
class NLA_HT_header(Header):
bl_space_type = 'NLA_EDITOR'
def draw(self, context):
layout = self.layout
st = context.space_data
layout.template_header()
NLA_MT_editor_menus.draw_collapsible(context, layout)
layout.separator_spacer()
dopesheet_filter(layout, context)
layout.popover(
panel="NLA_PT_filters",
text="",
icon='FILTER',
)
layout.prop(st, "auto_snap", text="")
class NLA_PT_filters(DopesheetFilterPopoverBase, Panel):
bl_space_type = 'NLA_EDITOR'
bl_region_type = 'HEADER'
bl_label = "Filters"
def draw(self, context):
layout = self.layout
DopesheetFilterPopoverBase.draw_generic_filters(context, layout)
layout.separator()
DopesheetFilterPopoverBase.draw_search_filters(context, layout)
layout.separator()
DopesheetFilterPopoverBase.draw_standard_filters(context, layout)
class NLA_PT_action(DopesheetActionPanelBase, Panel):
bl_space_type = 'NLA_EDITOR'
bl_category = "Strip"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
strip = context.active_nla_strip
return strip and strip.type == 'CLIP' and strip.action
def draw(self, context):
action = context.active_nla_strip.action
self.draw_generic_panel(context, self.layout, action)
class NLA_MT_editor_menus(Menu):
bl_idname = "NLA_MT_editor_menus"
bl_label = ""
def draw(self, context):
st = context.space_data
layout = self.layout
layout.menu("NLA_MT_view")
layout.menu("NLA_MT_select")
if st.show_markers:
layout.menu("NLA_MT_marker")
layout.menu("NLA_MT_edit")
layout.menu("NLA_MT_add")
class NLA_MT_view(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
st = context.space_data
layout.prop(st, "show_region_ui")
layout.prop(st, "show_region_hud")
layout.separator()
layout.prop(st, "use_realtime_update")
layout.prop(st, "show_seconds")
layout.prop(st, "show_locked_time")
layout.prop(st, "show_strip_curves")
layout.separator()
layout.prop(st, "show_markers")
layout.prop(st, "show_local_markers")
layout.separator()
layout.operator("anim.previewrange_set")
layout.operator("anim.previewrange_clear")
layout.operator("nla.previewrange_set")
layout.separator()
layout.operator("nla.view_all")
layout.operator("nla.view_selected")
layout.operator("nla.view_frame")
layout.separator()
layout.menu("INFO_MT_area")
class NLA_MT_select(Menu):
bl_label = "Select"
def draw(self, _context):
layout = self.layout
layout.operator("nla.select_all", text="All").action = 'SELECT'
layout.operator("nla.select_all", text="None").action = 'DESELECT'
layout.operator("nla.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("nla.select_box").axis_range = False
layout.operator("nla.select_box", text="Box Select (Axis Range)").axis_range = True
layout.separator()
props = layout.operator("nla.select_leftright", text="Before Current Frame")
props.extend = False
props.mode = 'LEFT'
props = layout.operator("nla.select_leftright", text="After Current Frame")
props.extend = False
props.mode = 'RIGHT'
class NLA_MT_marker(Menu):
bl_label = "Marker"
def draw(self, context):
layout = self.layout
from bl_ui.space_time import marker_menu_generic
marker_menu_generic(layout, context)
class NLA_MT_marker_select(Menu):
bl_label = 'Select'
def draw(self, _context):
layout = self.layout
layout.operator("marker.select_all", text="All").action = 'SELECT'
layout.operator("marker.select_all", text="None").action = 'DESELECT'
layout.operator("marker.select_all", text="Invert").action = 'INVERT'
layout.separator()
layout.operator("marker.select_leftright", text="Before Current Frame").mode = 'LEFT'
layout.operator("marker.select_leftright", text="After Current Frame").mode = 'RIGHT'
class NLA_MT_edit(Menu):
bl_label = "Edit"
def draw(self, context):
layout = self.layout
scene = context.scene
layout.menu("NLA_MT_edit_transform", text="Transform")
layout.operator_menu_enum("nla.snap", "type", text="Snap")
layout.separator()
layout.operator("nla.bake", text="Bake Action")
layout.operator("nla.duplicate", text="Duplicate").linked = False
layout.operator("nla.duplicate", text="Linked Duplicate").linked = True
layout.operator("nla.split")
layout.operator("nla.delete")
layout.operator("nla.tracks_delete")
layout.separator()
layout.operator("nla.mute_toggle")
layout.separator()
layout.operator("nla.apply_scale")
layout.operator("nla.clear_scale")
layout.operator("nla.action_sync_length").active = False
layout.separator()
layout.operator("nla.make_single_user")
layout.separator()
layout.operator("nla.swap")
layout.operator("nla.move_up")
layout.operator("nla.move_down")
# TODO: this really belongs more in a "channel" (or better, "track") menu
layout.separator()
layout.operator_menu_enum("anim.channels_move", "direction", text="Track Ordering...")
layout.operator("anim.channels_clean_empty")
layout.separator()
# TODO: names of these tools for 'tweak-mode' need changing?
if scene.is_nla_tweakmode:
layout.operator("nla.tweakmode_exit", text="Stop Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_exit", text="Stop Tweaking Strip Actions")
else:
layout.operator("nla.tweakmode_enter", text="Start Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_enter",
text="Start Tweaking Strip Actions (Full Stack)").use_upper_stack_evaluation = True
layout.operator("nla.tweakmode_enter",
text="Start Tweaking Strip Actions (Lower Stack)").use_upper_stack_evaluation = False
class NLA_MT_add(Menu):
bl_label = "Add"
bl_translation_context = i18n_contexts.operator_default
def draw(self, _context):
layout = self.layout
layout.operator("nla.actionclip_add")
layout.operator("nla.transition_add")
layout.operator("nla.soundclip_add")
layout.separator()
layout.operator("nla.meta_add")
layout.operator("nla.meta_remove")
layout.separator()
layout.operator("nla.tracks_add").above_selected = False
layout.operator("nla.tracks_add", text="Add Tracks Above Selected").above_selected = True
layout.separator()
layout.operator("nla.selected_objects_add")
class NLA_MT_edit_transform(Menu):
bl_label = "Transform"
def draw(self, _context):
layout = self.layout
layout.operator("transform.translate", text="Move")
layout.operator("transform.transform", text="Extend").mode = 'TIME_EXTEND'
layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE'
class NLA_MT_snap_pie(Menu):
bl_label = "Snap"
def draw(self, _context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("nla.snap", text="Selection to Current Frame").type = 'CFRA'
pie.operator("nla.snap", text="Selection to Nearest Frame").type = 'NEAREST_FRAME'
pie.operator("nla.snap", text="Selection to Nearest Second").type = 'NEAREST_SECOND'
pie.operator("nla.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER'
class NLA_MT_view_pie(Menu):
bl_label = "View"
def draw(self, _context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("nla.view_all")
pie.operator("nla.view_selected", icon='ZOOM_SELECTED')
pie.operator("nla.view_frame")
class NLA_MT_context_menu(Menu):
bl_label = "NLA Context Menu"
def draw(self, context):
layout = self.layout
scene = context.scene
if scene.is_nla_tweakmode:
layout.operator("nla.tweakmode_exit", text="Stop Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_exit", text="Stop Tweaking Strip Actions")
else:
layout.operator("nla.tweakmode_enter", text="Start Editing Stashed Action").isolate_action = True
layout.operator("nla.tweakmode_enter",
text="Start Tweaking Strip Actions (Full Stack)").use_upper_stack_evaluation = True
layout.operator("nla.tweakmode_enter",
text="Start Tweaking Strip Actions (Lower Stack)").use_upper_stack_evaluation = False
layout.separator()
props = layout.operator("wm.call_panel", text="Rename...")
props.name = "TOPBAR_PT_name"
props.keep_open = False
layout.operator("nla.duplicate", text="Duplicate").linked = False
layout.operator("nla.duplicate", text="Linked Duplicate").linked = True
layout.separator()
layout.operator("nla.split")
layout.operator("nla.delete")
layout.separator()
layout.operator("nla.swap")
layout.separator()
layout.operator_menu_enum("nla.snap", "type", text="Snap")
class NLA_MT_channel_context_menu(Menu):
bl_label = "NLA Channel Context Menu"
def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("anim.channels_move", "direction", text="Track Ordering...")
layout.operator("anim.channels_clean_empty")
classes = (
NLA_HT_header,
NLA_MT_edit,
NLA_MT_editor_menus,
NLA_MT_view,
NLA_MT_select,
NLA_MT_marker,
NLA_MT_marker_select,
NLA_MT_add,
NLA_MT_edit_transform,
NLA_MT_snap_pie,
NLA_MT_view_pie,
NLA_MT_context_menu,
NLA_MT_channel_context_menu,
NLA_PT_filters,
NLA_PT_action,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)