UI: Tree View: Operator to delete with X key

Tree view elements can be deleted by the remove operator located on the
right side with `-` icon. But these operators are different for every
type. Now introduced `UI_OT_view_item_delete`. With that it is possible
to delete elements with X key when mouse is over tree view. In future
maybe we could remove type specific operators (for example: `GREASE_PENCIL_OT_layer_remove`).

See video in PR description

Pull Request: https://projects.blender.org/blender/blender/pulls/144045
This commit is contained in:
Pratik Borhade
2025-08-16 08:21:49 +02:00
parent b856b6010e
commit e297fb4f14
9 changed files with 95 additions and 0 deletions

View File

@@ -1048,6 +1048,8 @@ def km_user_interface(_params):
("ui.view_item_select", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("range_select", True)]}),
("ui.view_item_rename", {"type": 'F2', "value": 'PRESS'}, None),
("ui.view_item_delete", {"type": 'X', "value": 'PRESS'}, None),
("ui.view_item_delete", {"type": 'DEL', "value": 'PRESS'}, None),
])
return keymap

View File

@@ -326,6 +326,8 @@ class AbstractViewItem {
void end_renaming();
void rename_apply(const bContext &C);
virtual void delete_item(bContext *C);
protected:
AbstractViewItem() = default;

View File

@@ -2830,6 +2830,33 @@ static void UI_OT_view_item_select(wmOperatorType *ot)
"Select all between clicked and active items");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
static wmOperatorStatus ui_view_item_delete_invoke(bContext *C,
wmOperator * /*op*/,
const wmEvent * /*event*/)
{
AbstractView *view = get_view_focused(C);
view->foreach_view_item([&](AbstractViewItem &item) {
if (item.is_active() || item.is_selected()) {
item.delete_item(C);
}
});
return OPERATOR_FINISHED;
}
static void UI_OT_view_item_delete(wmOperatorType *ot)
{
ot->name = "Delete";
ot->idname = "UI_OT_view_item_delete";
ot->description = "Delete selected list item";
ot->invoke = ui_view_item_delete_invoke;
ot->poll = ui_view_focused_poll;
ot->flag = OPTYPE_INTERNAL;
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -2934,6 +2961,7 @@ void ED_operatortypes_ui()
WM_operatortype_append(UI_OT_view_scroll);
WM_operatortype_append(UI_OT_view_item_rename);
WM_operatortype_append(UI_OT_view_item_select);
WM_operatortype_append(UI_OT_view_item_delete);
WM_operatortype_append(UI_OT_override_add_button);
WM_operatortype_append(UI_OT_override_remove_button);

View File

@@ -343,6 +343,11 @@ class BoneCollectionItem : public AbstractTreeViewItem {
return bone_collection_.name;
}
void delete_item(bContext *C) override
{
ANIM_armature_bonecoll_remove(&armature_, &bone_collection_);
ED_undo_push(C, "Delete Bone Collection");
}
std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const override
{
/* Reject dragging linked (or otherwise uneditable) bone collections. */

View File

@@ -284,6 +284,14 @@ class LayerViewItem : public AbstractTreeViewItem {
return layer_.name();
}
void delete_item(bContext *C) override
{
grease_pencil_.remove_layer(layer_);
DEG_id_tag_update(&grease_pencil_.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, nullptr);
ED_undo_push(C, "Delete Grease Pencil Layer");
}
std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const override
{
return std::make_unique<LayerViewItemDragController>(
@@ -446,6 +454,14 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
return group_.name();
}
void delete_item(bContext *C) override
{
grease_pencil_.remove_group(group_);
DEG_id_tag_update(&grease_pencil_.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, nullptr);
ED_undo_push(C, "Delete Grease Pencil Group");
}
std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const override
{
return std::make_unique<LayerViewItemDragController>(

View File

@@ -160,6 +160,15 @@ class NodeSocketViewItem : public BasicTreeViewItem {
return socket_.name;
}
void delete_item(bContext *C) override
{
Main *bmain = CTX_data_main(C);
nodetree_.tree_interface.remove_item(socket_.item);
BKE_main_ensure_invariants(*bmain, nodetree_.id);
WM_main_add_notifier(NC_NODE | NA_EDITED, &nodetree_);
ED_undo_push(C, "Delete Node Interface Socket");
}
std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const override;
std::unique_ptr<TreeViewItemDropTarget> create_drop_target() override;
};
@@ -232,6 +241,15 @@ class NodePanelViewItem : public BasicTreeViewItem {
return panel_.name;
}
void delete_item(bContext *C) override
{
Main *bmain = CTX_data_main(C);
nodetree_.tree_interface.remove_item(panel_.item);
BKE_main_ensure_invariants(*bmain, nodetree_.id);
WM_main_add_notifier(NC_NODE | NA_EDITED, &nodetree_);
ED_undo_push(C, "Delete Node Interface Panel");
}
std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const override;
std::unique_ptr<TreeViewItemDropTarget> create_drop_target() override;
};

View File

@@ -240,6 +240,11 @@ void AbstractViewItem::add_rename_button(uiBlock &block)
}
}
void AbstractViewItem::delete_item(bContext * /*C*/)
{
/* No deletion by default. Needs type specific implementation. */
}
/** \} */
/* ---------------------------------------------------------------------- */

View File

@@ -10,6 +10,7 @@
#include "BKE_context.hh"
#include "BKE_key.hh"
#include "BKE_object.hh"
#include "BLI_listbase.h"
#include "BLT_translation.hh"
@@ -236,6 +237,15 @@ class ShapeKeyItem : public ui::AbstractTreeViewItem {
return label_;
}
void delete_item(bContext *C) override
{
Main *bmain = CTX_data_main(C);
BKE_object_shapekey_remove(bmain, shape_key_.object, shape_key_.kb);
DEG_id_tag_update(&shape_key_.object->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, nullptr);
ED_undo_grouped_push(C, "Delete Shape Key");
}
void build_context_menu(bContext &C, uiLayout &layout) const override
{
MenuType *mt = WM_menutype_find("MESH_MT_shape_key_tree_context_menu", true);

View File

@@ -20,6 +20,7 @@
#include "BLT_translation.hh"
#include "ED_asset.hh"
#include "ED_asset_catalog.hh"
#include "ED_fileselect.hh"
#include "ED_undo.hh"
@@ -88,6 +89,7 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
bool supports_renaming() const override;
bool rename(const bContext &C, StringRefNull new_name) override;
void delete_item(bContext *C) override;
/** Add drag support for catalog items. */
std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
@@ -339,6 +341,13 @@ bool AssetCatalogTreeViewItem::rename(const bContext &C, StringRefNull new_name)
return true;
}
void AssetCatalogTreeViewItem::delete_item(bContext * /*C*/)
{
const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
this->get_tree_view());
ed::asset::catalog_remove(tree_view.asset_library_, catalog_item_.get_catalog_id());
}
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewItem::create_drop_target()
{
return std::make_unique<AssetCatalogDropTarget>(*this, catalog_item_);