diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index e665f7b1d52..74fa5cdeb9d 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -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(®ion->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) diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 7f530408ec7..b3ae336aadf 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -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)); diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 2f3fa6996af..ee1193af8d0 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -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); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index d55fd06ddea..7671547363b 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -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); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 74aff6a290b..6e6b0a584cf 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -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); }