# SPDX-FileCopyrightText: 2023 Blender Authors # # SPDX-License-Identifier: GPL-2.0-or-later """NOTE: this is temporary UI code to show animation layers. It is not meant for any particular use, just to have *something* in the UI. """ import threading import bpy from bpy.types import ( Panel, WindowManager, ) from bpy.props import PointerProperty class VIEW3D_PT_animation_layers(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = "Animation" bl_label = "Baklava" @classmethod def poll(cls, context): return context.preferences.experimental.use_animation_baklava and context.object def draw(self, context) -> None: layout = self.layout layout.use_property_split = True layout.use_property_decorate = False # FIXME: this should be done in response to a message-bus callback, notifier, whatnot. adt = context.object.animation_data with _wm_selected_action_lock: selected_action = getattr(adt, "action", None) # Only set if it has to change, to avoid unnecessary notifies (that cause # a redraw, that cause this code to be called, etc.) if context.window_manager.selected_action != selected_action: context.window_manager.selected_action = selected_action col = layout.column() # This has to go via an auxiliary property, as assigning an Animation # data-block should be possible even when `context.object.animation_data` # is `None`, and thus its `animation` property does not exist. col.template_ID(context.window_manager, "selected_action") col = layout.column(align=False) anim = adt and adt.action if anim: binding_sub = col.column(align=True) # Binding selector. row = binding_sub.row(align=True) row.prop(adt, "action_binding", text="Binding") row.operator("anim.binding_unassign_object", text="", icon='X') binding = anim.bindings.get(adt.action_binding, None) if binding: binding_sub.prop(binding, "name_display", text="Name") internal_sub = binding_sub.box().column(align=True) internal_sub.active = False internal_sub.prop(adt, "action_binding_handle", text="handle") if binding: internal_sub.prop(binding, "name", text="Internal Name") if adt: col.prop(adt, "action_binding_name", text="ADT Binding Name") else: col.label(text="ADT Binding Name: -") layout.separator() if not anim: layout.label(text="No layers") return for layer_idx, layer in reversed(list(enumerate(anim.layers))): layerbox = layout.box() col = layerbox.column(align=True) col.prop(layer, "name", text="Layer {:d}:".format(layer_idx + 1)) col.prop(layer, "influence") col.prop(layer, "mix_mode") classes = ( VIEW3D_PT_animation_layers, ) _wm_selected_action_lock = threading.Lock() def _wm_selected_action_update(wm, context): # Avoid responding to changes written by the panel above. lock_ok = _wm_selected_action_lock.acquire(blocking=False) if not lock_ok: return try: if wm.selected_action is None and context.object.animation_data is None: return adt = context.object.animation_data_create() if adt.action == wm.selected_action: # Avoid writing to the property when the new value hasn't changed. return adt.action = wm.selected_action finally: _wm_selected_action_lock.release() def register_props(): # Due to this hackyness, the WindowManager will increase the user count of # the pointed-to Animation data-block. WindowManager.selected_action = PointerProperty( type=bpy.types.Action, name="Action", description="Action assigned to the active Object", update=_wm_selected_action_update, ) if __name__ == "__main__": # only for live edit. register_, _ = bpy.utils.register_classes_factory(classes) register_() register_props()