mirror of
https://projects.blender.org/blender/blender.git
synced 2025-01-22 15:32:15 -05:00
Anim: add Action+Slot selector for Masks
This adds an Animation panel to the Mask tab of the n-panel of the Movie Clip and Image editors. Masks can be animated (for example, the opacity of a Mask Layer), but there was no way to manage the Action and Slot that held those F-Curves. To keep things DRY, this PR also moves the code for drawing Action+Slot selectors from the `PropertiesAnimationMixin` class to a utility function, which is now called from both that class and the Mask UI code. Pull Request: https://projects.blender.org/blender/blender/pulls/133153
This commit is contained in:
parent
18f145d1ac
commit
b2a06888c7
5 changed files with 71 additions and 15 deletions
|
@ -5,6 +5,33 @@
|
||||||
from bpy.types import Menu
|
from bpy.types import Menu
|
||||||
|
|
||||||
|
|
||||||
|
def draw_action_and_slot_selector_for_id(layout, animated_id):
|
||||||
|
"""
|
||||||
|
Draw the action and slot selector for an ID, using the given layout.
|
||||||
|
|
||||||
|
The ID must be an animatable ID.
|
||||||
|
|
||||||
|
Note that the slot selector is only drawn when the ID has an assigned
|
||||||
|
Action.
|
||||||
|
"""
|
||||||
|
|
||||||
|
layout.template_action(animated_id, new="action.new", unlink="action.unlink")
|
||||||
|
|
||||||
|
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_suitable_slots",
|
||||||
|
new="anim.slot_new_for_id",
|
||||||
|
unlink="anim.slot_unassign_from_id",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ANIM_MT_keyframe_insert_pie(Menu):
|
class ANIM_MT_keyframe_insert_pie(Menu):
|
||||||
bl_label = "Keyframe Insert Pie"
|
bl_label = "Keyframe Insert Pie"
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
from bpy.types import Menu, UIList
|
from bpy.types import Menu, UIList
|
||||||
from bpy.app.translations import contexts as i18n_contexts
|
from bpy.app.translations import contexts as i18n_contexts
|
||||||
|
from . import anim
|
||||||
|
|
||||||
|
|
||||||
# Use by both image & clip context menus.
|
# Use by both image & clip context menus.
|
||||||
|
@ -222,6 +223,31 @@ class MASK_PT_point:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MASK_PT_animation:
|
||||||
|
# subclasses must define...
|
||||||
|
# ~ bl_space_type = 'CLIP_EDITOR'
|
||||||
|
# ~ bl_region_type = 'UI'
|
||||||
|
bl_label = "Animation"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
space_data = context.space_data
|
||||||
|
return space_data.mask and space_data.mode == 'MASK'
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.use_property_split = True
|
||||||
|
layout.use_property_decorate = False
|
||||||
|
|
||||||
|
# poll() ensures this is not None.
|
||||||
|
sc = context.space_data
|
||||||
|
mask = sc.mask
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
anim.draw_action_and_slot_selector_for_id(col, mask)
|
||||||
|
|
||||||
|
|
||||||
class MASK_PT_display:
|
class MASK_PT_display:
|
||||||
# subclasses must define...
|
# subclasses must define...
|
||||||
# ~ bl_space_type = 'CLIP_EDITOR'
|
# ~ bl_space_type = 'CLIP_EDITOR'
|
||||||
|
|
|
@ -1191,6 +1191,7 @@ from bl_ui.properties_mask_common import (
|
||||||
MASK_PT_layers,
|
MASK_PT_layers,
|
||||||
MASK_PT_spline,
|
MASK_PT_spline,
|
||||||
MASK_PT_point,
|
MASK_PT_point,
|
||||||
|
MASK_PT_animation,
|
||||||
MASK_PT_display,
|
MASK_PT_display,
|
||||||
MASK_PT_transforms,
|
MASK_PT_transforms,
|
||||||
MASK_PT_tools,
|
MASK_PT_tools,
|
||||||
|
@ -1215,6 +1216,12 @@ class CLIP_PT_active_mask_point(MASK_PT_point, Panel):
|
||||||
bl_category = "Mask"
|
bl_category = "Mask"
|
||||||
|
|
||||||
|
|
||||||
|
class CLIP_PT_mask_animation(MASK_PT_animation, Panel):
|
||||||
|
bl_space_type = 'CLIP_EDITOR'
|
||||||
|
bl_region_type = 'UI'
|
||||||
|
bl_category = "Mask"
|
||||||
|
|
||||||
|
|
||||||
class CLIP_PT_mask(MASK_PT_mask, Panel):
|
class CLIP_PT_mask(MASK_PT_mask, Panel):
|
||||||
bl_space_type = 'CLIP_EDITOR'
|
bl_space_type = 'CLIP_EDITOR'
|
||||||
bl_region_type = 'UI'
|
bl_region_type = 'UI'
|
||||||
|
@ -1996,6 +2003,7 @@ classes = (
|
||||||
CLIP_PT_mask_display,
|
CLIP_PT_mask_display,
|
||||||
CLIP_PT_active_mask_spline,
|
CLIP_PT_active_mask_spline,
|
||||||
CLIP_PT_active_mask_point,
|
CLIP_PT_active_mask_point,
|
||||||
|
CLIP_PT_mask_animation,
|
||||||
CLIP_PT_tools_mask_transforms,
|
CLIP_PT_tools_mask_transforms,
|
||||||
CLIP_PT_tools_mask_tools,
|
CLIP_PT_tools_mask_tools,
|
||||||
CLIP_PT_tools_scenesetup,
|
CLIP_PT_tools_scenesetup,
|
||||||
|
|
|
@ -987,6 +987,7 @@ from bl_ui.properties_mask_common import (
|
||||||
MASK_PT_layers,
|
MASK_PT_layers,
|
||||||
MASK_PT_spline,
|
MASK_PT_spline,
|
||||||
MASK_PT_point,
|
MASK_PT_point,
|
||||||
|
MASK_PT_animation,
|
||||||
MASK_PT_display,
|
MASK_PT_display,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1015,6 +1016,12 @@ class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
|
||||||
bl_category = "Mask"
|
bl_category = "Mask"
|
||||||
|
|
||||||
|
|
||||||
|
class IMAGE_PT_mask_animation(MASK_PT_animation, Panel):
|
||||||
|
bl_space_type = 'IMAGE_EDITOR'
|
||||||
|
bl_region_type = 'UI'
|
||||||
|
bl_category = "Mask"
|
||||||
|
|
||||||
|
|
||||||
class IMAGE_PT_mask_display(MASK_PT_display, Panel):
|
class IMAGE_PT_mask_display(MASK_PT_display, Panel):
|
||||||
bl_space_type = 'IMAGE_EDITOR'
|
bl_space_type = 'IMAGE_EDITOR'
|
||||||
bl_region_type = 'HEADER'
|
bl_region_type = 'HEADER'
|
||||||
|
@ -1771,6 +1778,7 @@ classes = (
|
||||||
IMAGE_PT_mask_display,
|
IMAGE_PT_mask_display,
|
||||||
IMAGE_PT_active_mask_spline,
|
IMAGE_PT_active_mask_spline,
|
||||||
IMAGE_PT_active_mask_point,
|
IMAGE_PT_active_mask_point,
|
||||||
|
IMAGE_PT_mask_animation,
|
||||||
IMAGE_PT_snapping,
|
IMAGE_PT_snapping,
|
||||||
IMAGE_PT_proportional_edit,
|
IMAGE_PT_proportional_edit,
|
||||||
IMAGE_PT_image_properties,
|
IMAGE_PT_image_properties,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
from bpy.types import Header, Panel
|
from bpy.types import Header, Panel
|
||||||
from rna_prop_ui import PropertyPanel
|
from rna_prop_ui import PropertyPanel
|
||||||
|
from . import anim
|
||||||
|
|
||||||
|
|
||||||
class PROPERTIES_HT_header(Header):
|
class PROPERTIES_HT_header(Header):
|
||||||
|
@ -122,21 +123,7 @@ class PropertiesAnimationMixin:
|
||||||
layout.label(text="No animatable data-block, please report as bug", icon='ERROR')
|
layout.label(text="No animatable data-block, please report as bug", icon='ERROR')
|
||||||
return
|
return
|
||||||
|
|
||||||
layout.template_action(animated_id, new="action.new", unlink="action.unlink")
|
anim.draw_action_and_slot_selector_for_id(layout, animated_id)
|
||||||
|
|
||||||
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_suitable_slots",
|
|
||||||
new="anim.slot_new_for_id",
|
|
||||||
unlink="anim.slot_unassign_from_id",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
|
|
Loading…
Reference in a new issue