Add two new operators, `anim.slot_new_for_id` and `anim.slot_unassign_from_id`. These are used in the Action editor and the Animation panels in the Properties editor, to respectively create a new Action Slot for an ID and to unassign whatever slot is currently assigned to that ID. The latter operator also replaces the C++ operator `anim.slot_unassign_object`, which was specifically made for the Dopesheet header. The Python ones are generic enough to be used there too. Pull Request: https://projects.blender.org/blender/blender/pulls/126943
147 lines
4.5 KiB
Python
147 lines
4.5 KiB
Python
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
from bpy.types import Header, Panel
|
|
from rna_prop_ui import PropertyPanel
|
|
|
|
|
|
class PROPERTIES_HT_header(Header):
|
|
bl_space_type = 'PROPERTIES'
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
view = context.space_data
|
|
region = context.region
|
|
ui_scale = context.preferences.system.ui_scale
|
|
|
|
layout.template_header()
|
|
|
|
layout.separator_spacer()
|
|
|
|
# The following is an ugly attempt to make the search button center-align better visually.
|
|
# A dummy icon is inserted that has to be scaled as the available width changes.
|
|
content_size_est = 160 * ui_scale
|
|
layout_scale = min(1, max(0, (region.width / content_size_est) - 1))
|
|
if layout_scale > 0:
|
|
row = layout.row()
|
|
row.scale_x = layout_scale
|
|
row.label(icon='BLANK1')
|
|
|
|
layout.prop(view, "search_filter", icon='VIEWZOOM', text="")
|
|
|
|
layout.separator_spacer()
|
|
|
|
layout.popover(panel="PROPERTIES_PT_options", text="")
|
|
|
|
|
|
class PROPERTIES_PT_navigation_bar(Panel):
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'NAVIGATION_BAR'
|
|
bl_label = "Navigation Bar"
|
|
bl_options = {'HIDE_HEADER'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
view = context.space_data
|
|
|
|
layout.scale_x = 1.4
|
|
layout.scale_y = 1.4
|
|
if view.search_filter:
|
|
layout.prop_tabs_enum(
|
|
view, "context", data_highlight=view,
|
|
property_highlight="tab_search_results", icon_only=True,
|
|
)
|
|
else:
|
|
layout.prop_tabs_enum(view, "context", icon_only=True)
|
|
|
|
|
|
class PROPERTIES_PT_options(Panel):
|
|
"""Show options for the properties editor"""
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'HEADER'
|
|
bl_label = "Options"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
space = context.space_data
|
|
|
|
col = layout.column()
|
|
col.label(text="Sync with Outliner")
|
|
col.row().prop(space, "outliner_sync", expand=True)
|
|
|
|
|
|
class PropertiesAnimationMixin:
|
|
"""Mix-in class for Animation panels.
|
|
|
|
This class can be used to show a generic 'Animation' panel for IDs shown in
|
|
the properties editor. Specific ID types need specific subclasses.
|
|
|
|
For an example, see DATA_PT_camera_animation in properties_data_camera.py
|
|
"""
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "data"
|
|
bl_label = "Animation"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
bl_order = PropertyPanel.bl_order - 1 # Order just above the Custom Properties.
|
|
|
|
_animated_id_context_property = ""
|
|
"""context.{_animatable_id_context_property} is used to find the animated ID."""
|
|
|
|
@classmethod
|
|
def _animated_id(cls, context):
|
|
assert cls._animated_id_context_property, f'set _animated_id_context_property on {cls}'
|
|
|
|
# If the pinned ID is of a different type, there could still be a an ID
|
|
# for which to show this panel. For example, a camera object can be
|
|
# pinned, and then this panel can be shown for its camera data.
|
|
return getattr(context, cls._animated_id_context_property, None)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
animated_id = cls._animated_id(context)
|
|
return animated_id is not None
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
col = layout.column(align=True)
|
|
col.use_property_split = True
|
|
self.draw_action_and_slot_selector(context, col, self._animated_id(context))
|
|
|
|
@staticmethod
|
|
def draw_action_and_slot_selector(context, layout, animated_id):
|
|
layout.template_action(animated_id, new="action.new", unlink="action.unlink")
|
|
|
|
if not context.preferences.experimental.use_animation_baklava:
|
|
return
|
|
|
|
adt = animated_id.animation_data
|
|
if not adt or not adt.action:
|
|
return
|
|
|
|
# Only show the slot selector when a layered Action is assigned.
|
|
if adt.action.is_action_layered:
|
|
layout.context_pointer_set("animated_id", animated_id)
|
|
layout.template_search(
|
|
adt, "action_slot",
|
|
adt, "action_slots",
|
|
new="anim.slot_new_for_id",
|
|
unlink="anim.slot_unassign_from_id",
|
|
)
|
|
|
|
|
|
classes = (
|
|
PROPERTIES_HT_header,
|
|
PROPERTIES_PT_navigation_bar,
|
|
PROPERTIES_PT_options,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
for cls in classes:
|
|
register_class(cls)
|