Anim: Show action slots in the outliner

Add Slots to the outliner.
Slots can be renamed from the outliner.

Pull Request: https://projects.blender.org/blender/blender/pulls/126839
This commit is contained in:
Christoph Lendenfeld
2025-05-08 16:09:31 +02:00
committed by Christoph Lendenfeld
parent e0beb7afe6
commit d30d4c0c04
11 changed files with 144 additions and 3 deletions

View File

@@ -41,6 +41,7 @@ set(SRC
tree/tree_display_sequencer.cc
tree/tree_display_view_layer.cc
tree/tree_element.cc
tree/tree_element_action_slot.cc
tree/tree_element_anim_data.cc
tree/tree_element_bone.cc
tree/tree_element_bone_collection.cc
@@ -53,6 +54,7 @@ set(SRC
tree/tree_element_gpencil_layer.cc
tree/tree_element_grease_pencil_node.cc
tree/tree_element_id.cc
tree/tree_element_id_action.cc
tree/tree_element_id_armature.cc
tree/tree_element_id_collection.cc
tree/tree_element_id_curve.cc
@@ -85,6 +87,7 @@ set(SRC
tree/common.hh
tree/tree_display.hh
tree/tree_element.hh
tree/tree_element_action_slot.hh
tree/tree_element_anim_data.hh
tree/tree_element_bone.hh
tree/tree_element_bone_collection.hh
@@ -97,6 +100,7 @@ set(SRC
tree/tree_element_gpencil_layer.hh
tree/tree_element_grease_pencil_node.hh
tree/tree_element_id.hh
tree/tree_element_id_action.hh
tree/tree_element_id_armature.hh
tree/tree_element_id_collection.hh
tree/tree_element_id_curve.hh

View File

@@ -932,6 +932,12 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
undo_str = "Rename Bone Collection";
break;
}
case TSE_ACTION_SLOT: {
WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
undo_str = "Rename Action Slot";
break;
}
}
}
tselem->flag &= ~TSE_TEXTBUT;
@@ -2603,6 +2609,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
if (tselem->type != TSE_SOME_ID) {
switch (tselem->type) {
case TSE_ACTION_SLOT:
data.icon = ICON_ACTION_SLOT;
break;
case TSE_ANIM_DATA:
data.icon = ICON_ANIM_DATA; /* XXX */
break;
@@ -3172,7 +3181,8 @@ static void outliner_draw_iconrow(uiBlock *block,
TSE_EBONE,
TSE_POSE_CHANNEL,
TSE_BONE_COLLECTION,
TSE_DEFGROUP))
TSE_DEFGROUP,
TSE_ACTION_SLOT))
{
outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1);
}

View File

@@ -308,6 +308,9 @@ TreeElement *AbstractTreeDisplay::add_element(ListBase *lb,
else if (ELEM(type, TSE_ANIM_DATA, TSE_NLA, TSE_NLA_TRACK, TSE_DRIVER_BASE)) {
/* pass */
}
else if (ELEM(type, TSE_ACTION_SLOT)) {
/* pass */
}
else if (ELEM(type, TSE_GP_LAYER, TSE_GREASE_PENCIL_NODE)) {
/* pass */
}

View File

@@ -16,6 +16,7 @@
#include "UI_resources.hh"
#include "tree_display.hh"
#include "tree_element_action_slot.hh"
#include "tree_element_anim_data.hh"
#include "tree_element_bone.hh"
#include "tree_element_bone_collection.hh"
@@ -200,6 +201,9 @@ std::unique_ptr<AbstractTreeElement> AbstractTreeElement::create_from_type(const
legacy_te,
*reinterpret_cast<bArmature *>(owner_id),
*static_cast<BoneCollection *>(create_data));
case TSE_ACTION_SLOT:
return std::make_unique<TreeElementActionSlot>(
legacy_te, *reinterpret_cast<blender::animrig::Slot *>(create_data));
default:
break;

View File

@@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#include "DNA_action_types.h"
#include "../outliner_intern.hh"
#include "tree_element_action_slot.hh"
#include "ANIM_action.hh"
namespace blender::ed::outliner {
TreeElementActionSlot::TreeElementActionSlot(TreeElement &legacy_te, blender::animrig::Slot &slot)
: AbstractTreeElement(legacy_te)
{
legacy_te.name = &slot.identifier[2];
legacy_te.directdata = &slot;
}
} // namespace blender::ed::outliner

View File

@@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#pragma once
#include "tree_element.hh"
struct bAction;
namespace blender::animrig {
class Slot;
}
namespace blender::ed::outliner {
class TreeElementActionSlot final : public AbstractTreeElement {
public:
TreeElementActionSlot(TreeElement &legacy_te, blender::animrig::Slot &slot);
};
} // namespace blender::ed::outliner

View File

@@ -13,6 +13,7 @@
#include "../outliner_intern.hh"
#include "common.hh"
#include "tree_element_id_action.hh"
#include "tree_element_id_armature.hh"
#include "tree_element_id_collection.hh"
#include "tree_element_id_curve.hh"
@@ -62,6 +63,8 @@ std::unique_ptr<TreeElementID> TreeElementID::create_from_id(TreeElement &legacy
return std::make_unique<TreeElementIDArmature>(legacy_te, (bArmature &)id);
case ID_OB:
return std::make_unique<TreeElementIDObject>(legacy_te, (Object &)id);
case ID_AC:
return std::make_unique<TreeElementIDAction>(legacy_te, (bAction &)id);
case ID_MA:
case ID_LT:
case ID_LA:
@@ -85,7 +88,6 @@ std::unique_ptr<TreeElementID> TreeElementID::create_from_id(TreeElement &legacy
case ID_VF:
case ID_TXT:
case ID_SO:
case ID_AC:
case ID_PAL:
case ID_PC:
case ID_CF:

View File

@@ -0,0 +1,38 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#include "DNA_action_types.h"
#include "DNA_outliner_types.h"
#include "../outliner_intern.hh"
#include "tree_element_id_action.hh"
#include "ANIM_action.hh"
namespace blender::ed::outliner {
TreeElementIDAction::TreeElementIDAction(TreeElement &legacy_te, bAction &action)
: TreeElementID(legacy_te, action.id), action_(action)
{
}
void TreeElementIDAction::expand(SpaceOutliner & /* space_outliner */) const
{
blender::animrig::Action &action = action_.wrap();
for (blender::animrig::Slot *slot : action.slots()) {
add_element(&legacy_te_.subtree,
reinterpret_cast<ID *>(&action_),
slot,
&legacy_te_,
TSE_ACTION_SLOT,
0);
}
}
} // namespace blender::ed::outliner

View File

@@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#pragma once
#include "tree_element_id.hh"
struct bAction;
namespace blender::ed::outliner {
class TreeElementIDAction final : public TreeElementID {
bAction &action_;
public:
TreeElementIDAction(TreeElement &legacy_te, bAction &action);
void expand(SpaceOutliner &space_outliner) const override;
};
} // namespace blender::ed::outliner

View File

@@ -115,6 +115,7 @@ typedef enum eTreeStoreElemType {
TSE_GENERIC_LABEL = 47, /* No ID */
TSE_GREASE_PENCIL_NODE = 48,
TSE_LINKED_NODE_TREE = 49,
TSE_ACTION_SLOT = 50,
} eTreeStoreElemType;
/** Check whether given #TreeStoreElem should have a real ID in #TreeStoreElem.id member. */

View File

@@ -2163,7 +2163,8 @@ static void rna_def_action_slot(BlenderRNA *brna)
"rna_ActionSlot_name_display_length",
"rna_ActionSlot_name_display_set");
RNA_def_property_string_maxlength(prop, sizeof(ActionSlot::identifier) - 2);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, "rna_ActionSlot_identifier_update");
RNA_def_property_update(
prop, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, "rna_ActionSlot_identifier_update");
RNA_def_property_ui_text(
prop,
"Slot Display Name",