From 4f722eaae352b32d628c3d77ab9a2eff4b3da71c Mon Sep 17 00:00:00 2001 From: Habib Gahbiche Date: Tue, 30 Sep 2025 11:46:32 +0200 Subject: [PATCH] Compositor: "Copy" button duplicates node tree Currently, the compositor template ID creates a new node tree. This is inconsistent with other node editors where the button copies the node tree. Also use "New" in geometry nodes operator description instead of "Copy" Pull Request: https://projects.blender.org/blender/blender/pulls/146222 --- scripts/startup/bl_ui/space_node.py | 5 +- .../blender/editors/object/object_modifier.cc | 5 +- source/blender/editors/space_node/node_add.cc | 99 ++++++++++++++----- .../blender/editors/space_node/node_intern.hh | 1 + source/blender/editors/space_node/node_ops.cc | 1 + 5 files changed, 81 insertions(+), 30 deletions(-) diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 01ad3dd72d6..b8dd0a305fe 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -152,7 +152,10 @@ class NODE_HT_header(Header): if snode.node_tree_sub_type == 'SCENE': row = layout.row() row.enabled = not snode.pin - row.template_ID(scene, "compositing_node_group", new="node.new_compositing_node_group") + if scene.compositing_node_group: + row.template_ID(scene, "compositing_node_group", new="node.duplicate_compositing_node_group") + else: + row.template_ID(scene, "compositing_node_group", new="node.new_compositing_node_group") elif snode.node_tree_sub_type == 'SEQUENCER': row = layout.row() sequencer_scene = context.workspace.sequencer_scene diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index bcd36e842ac..448eb26aeed 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -3594,8 +3594,9 @@ static wmOperatorStatus geometry_node_tree_copy_assign_exec(bContext *C, wmOpera void OBJECT_OT_geometry_node_tree_copy_assign(wmOperatorType *ot) { - ot->name = "Copy Geometry Node Group"; - ot->description = "Copy the active geometry node group and assign it to the active modifier"; + ot->name = "New Geometry Node Group"; + ot->description = + "Duplicate the active geometry node group and assign it to the active modifier"; ot->idname = "OBJECT_OT_geometry_node_tree_copy_assign"; ot->exec = geometry_node_tree_copy_assign_exec; diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 81ddeae8028..b485a2f1a9b 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -114,6 +114,39 @@ bNode *add_static_node(const bContext &C, int type, const float2 &location) return node; } +/** + * Hook an existing node tree to a templateID UI button. + */ +static void node_templateID_assign(bContext *C, bNodeTree *node_tree) +{ + Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + + PointerRNA ptr; + PropertyRNA *prop; + + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + + if (prop) { + /* #RNA_property_pointer_set increases the user count, fixed here as the editor is the initial + * user. */ + id_us_min(&node_tree->id); + + if (ptr.owner_id) { + BKE_id_move_to_same_lib(*bmain, node_tree->id, *ptr.owner_id); + } + + PointerRNA idptr = RNA_id_pointer_create(&node_tree->id); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); + RNA_property_update(C, &ptr, prop); + } + else if (snode) { + snode->nodetree = node_tree; + + tree_update(C); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1595,34 +1628,9 @@ void NODE_OT_add_color(wmOperatorType *ot) static bNodeTree *new_node_tree_impl(bContext *C, StringRef treename, StringRef idname) { Main *bmain = CTX_data_main(C); - SpaceNode *snode = CTX_wm_space_node(C); - PointerRNA ptr; - PropertyRNA *prop; - bNodeTree *node_tree; - node_tree = bke::node_tree_add_tree(bmain, treename, idname); - - /* Hook into UI. */ - UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - - if (prop) { - /* #RNA_property_pointer_set increases the user count, fixed here as the editor is the initial - * user. */ - id_us_min(&node_tree->id); - - if (ptr.owner_id) { - BKE_id_move_to_same_lib(*bmain, node_tree->id, *ptr.owner_id); - } - - PointerRNA idptr = RNA_id_pointer_create(&node_tree->id); - RNA_property_pointer_set(&ptr, prop, idptr, nullptr); - RNA_property_update(C, &ptr, prop); - } - else if (snode) { - snode->nodetree = node_tree; - - tree_update(C); - } + bNodeTree *node_tree = bke::node_tree_add_tree(bmain, treename, idname); + node_templateID_assign(C, node_tree); return node_tree; } @@ -1749,6 +1757,43 @@ void NODE_OT_new_compositing_node_group(wmOperatorType *ot) RNA_def_string(ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", ""); } +/* -------------------------------------------------------------------- */ +/** \name Duplicate Compositing Node Tree Operator + * \{ */ + +static wmOperatorStatus duplicate_compositing_node_group_exec(bContext *C, wmOperator * /*op*/) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + PointerRNA ptr; + + if (scene->compositing_node_group == nullptr) { + return OPERATOR_CANCELLED; + } + + bNodeTree *node_tree = bke::node_tree_copy_tree(bmain, *scene->compositing_node_group); + + node_templateID_assign(C, node_tree); + + WM_event_add_notifier(C, NC_NODE | NA_ADDED, nullptr); + BKE_ntree_update_after_single_tree_change(*bmain, *node_tree); + + return OPERATOR_FINISHED; +} + +void NODE_OT_duplicate_compositing_node_group(wmOperatorType *ot) +{ + ot->name = "New Compositing Node Group"; + ot->idname = "NODE_OT_duplicate_compositing_node_group"; + ot->description = "Duplicate the currently assigned compositing node group."; + + ot->exec = duplicate_compositing_node_group_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name New Compositor Sequencer Node Group Operator * \{ */ diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 6cb295eddda..3cef95d05c1 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -310,6 +310,7 @@ void NODE_OT_add_import_node(wmOperatorType *ot); void NODE_OT_swap_group_asset(wmOperatorType *ot); void NODE_OT_new_node_tree(wmOperatorType *ot); void NODE_OT_new_compositing_node_group(wmOperatorType *ot); +void NODE_OT_duplicate_compositing_node_group(wmOperatorType *ot); void NODE_OT_new_compositor_sequencer_node_group(wmOperatorType *operator_type); void NODE_OT_add_group_input_node(wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index 70cdb44fa62..de817be1271 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -95,6 +95,7 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_new_node_tree); WM_operatortype_append(NODE_OT_new_compositing_node_group); + WM_operatortype_append(NODE_OT_duplicate_compositing_node_group); WM_operatortype_append(NODE_OT_new_compositor_sequencer_node_group); WM_operatortype_append(NODE_OT_parent_set);