UI/Nodes: Adding node groups via drag & drop (e.g. from Asset Browser)

Adds `NODE_OT_add_group` operator to add a node group from a given name, and
uses that to register a node editor drop-box.
When dropping a node-group asset, the ID will be appended. This is what we do
for other ID assets too.

Should the node group insertion fail (e.g. the group is not compatible with the
current tree, as checked by the poll), the appended data-block is removed.

Differential Revision: https://developer.blender.org/D10405

Reviewed by: Jacques Lucke
This commit is contained in:
Julian Eisel 2021-02-15 19:35:24 +01:00
parent 45852532d5
commit 604e61d81d
Notes: blender-bot 2023-02-14 11:42:40 +01:00
Referenced by issue #97237, Asset Browser: dragging custom node group asset adds broken node
Referenced by issue #82661, Expand asset drag & drop support to more cases
5 changed files with 133 additions and 5 deletions

View File

@ -309,6 +309,111 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ****************** Add Node Group Operator ******************* */
static bNodeTree *node_add_group_get_and_poll_group_node_tree(Main *bmain,
wmOperator *op,
bNodeTree *ntree)
{
char name[MAX_ID_NAME - 2];
RNA_string_get(op->ptr, "name", name);
bNodeTree *node_group = (bNodeTree *)BKE_libblock_find_name(bmain, ID_NT, name);
if (!node_group) {
return NULL;
}
if ((node_group->type != ntree->type) || !nodeGroupPoll(ntree, node_group)) {
if (RNA_boolean_get(op->ptr, "free_id_on_error")) {
BKE_id_delete(bmain, node_group);
}
return NULL;
}
return node_group;
}
static int node_add_group_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
bNodeTree *node_group;
if (!(node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree))) {
return OPERATOR_CANCELLED;
}
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *group_node = node_add_node(C,
node_group_idname(C),
(node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
NODE_GROUP,
snode->runtime->cursor[0],
snode->runtime->cursor[1]);
if (!group_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node group");
return OPERATOR_CANCELLED;
}
group_node->id = &node_group->id;
id_us_plus(group_node->id);
nodeSetActive(ntree, group_node);
ntreeUpdateTree(bmain, node_group);
ntreeUpdateTree(bmain, ntree);
snode_notify(C, snode);
snode_dag_update(C, snode);
return OPERATOR_FINISHED;
}
static int node_add_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
SpaceNode *snode = CTX_wm_space_node(C);
/* Convert mouse coordinates to v2d space. */
UI_view2d_region_to_view(&region->v2d,
event->mval[0],
event->mval[1],
&snode->runtime->cursor[0],
&snode->runtime->cursor[1]);
snode->runtime->cursor[0] /= UI_DPI_FAC;
snode->runtime->cursor[1] /= UI_DPI_FAC;
return node_add_group_exec(C, op);
}
void NODE_OT_add_group(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Add Node Group";
ot->description = "Add an existing node group to the current node editor";
ot->idname = "NODE_OT_add_group";
/* callbacks */
ot->exec = node_add_group_exec;
ot->invoke = node_add_group_invoke;
ot->poll = ED_operator_node_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
prop = RNA_def_boolean(
ot->srna,
"free_id_on_error",
false,
"Free Group on Error",
"Free the named node group data-block if it could not be added to the tree");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ****************** Add File Node Operator ******************* */
static bool node_add_file_poll(bContext *C)

View File

@ -107,7 +107,7 @@ static const char *group_ntree_idname(bContext *C)
return snode->tree_idname;
}
static const char *group_node_idname(bContext *C)
const char *node_group_idname(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
@ -147,7 +147,7 @@ static bNode *node_group_get_active(bContext *C, const char *node_idname)
static int node_group_edit_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
const char *node_idname = group_node_idname(C);
const char *node_idname = node_group_idname(C);
const bool exit = RNA_boolean_get(op->ptr, "exit");
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
@ -400,7 +400,7 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
const char *node_idname = group_node_idname(C);
const char *node_idname = node_group_idname(C);
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
@ -1013,7 +1013,7 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const char *ntree_idname = group_ntree_idname(C);
const char *node_idname = group_node_idname(C);
const char *node_idname = node_group_idname(C);
Main *bmain = CTX_data_main(C);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
@ -1070,7 +1070,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const char *node_idname = group_node_idname(C);
const char *node_idname = node_group_idname(C);
Main *bmain = CTX_data_main(C);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));

View File

@ -194,11 +194,13 @@ void draw_nodespace_back_pix(const struct bContext *C,
bNode *node_add_node(
const struct bContext *C, const char *idname, int type, float locx, float locy);
void NODE_OT_add_reroute(struct wmOperatorType *ot);
void NODE_OT_add_group(struct wmOperatorType *ot);
void NODE_OT_add_file(struct wmOperatorType *ot);
void NODE_OT_add_mask(struct wmOperatorType *ot);
void NODE_OT_new_node_tree(struct wmOperatorType *ot);
/* node_group.c */
const char *node_group_idname(struct bContext *C);
void NODE_OT_group_make(struct wmOperatorType *ot);
void NODE_OT_group_insert(struct wmOperatorType *ot);
void NODE_OT_group_ungroup(struct wmOperatorType *ot);

View File

@ -88,6 +88,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_backimage_fit);
WM_operatortype_append(NODE_OT_backimage_sample);
WM_operatortype_append(NODE_OT_add_group);
WM_operatortype_append(NODE_OT_add_file);
WM_operatortype_append(NODE_OT_add_mask);

View File

@ -659,6 +659,14 @@ static void node_main_region_draw(const bContext *C, ARegion *region)
/* ************* dropboxes ************* */
static bool node_group_drop_poll(bContext *UNUSED(C),
wmDrag *drag,
const wmEvent *UNUSED(event),
const char **UNUSED(r_tooltip))
{
return WM_drag_is_ID_type(drag, ID_NT);
}
static bool node_ima_drop_poll(bContext *UNUSED(C),
wmDrag *drag,
const wmEvent *UNUSED(event),
@ -679,6 +687,17 @@ static bool node_mask_drop_poll(bContext *UNUSED(C),
return WM_drag_is_ID_type(drag, ID_MSK);
}
static void node_group_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
if (drag->type == WM_DRAG_ASSET) {
/* ID just appended, so free it when dropping fails. */
RNA_boolean_set(drop->ptr, "free_id_on_error", true);
}
}
static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
@ -705,6 +724,7 @@ static void node_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
WM_dropbox_add(lb, "NODE_OT_add_group", node_group_drop_poll, node_group_drop_copy);
WM_dropbox_add(lb, "NODE_OT_add_file", node_ima_drop_poll, node_id_path_drop_copy);
WM_dropbox_add(lb, "NODE_OT_add_mask", node_mask_drop_poll, node_id_drop_copy);
}