From c0de8c40ee42a6f20f28daf66a017a90a347fb8a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 30 Sep 2025 13:30:49 +0200 Subject: [PATCH] Fix: Nodes: double clicking to enter/exit node group not reliable The issue was that the used operator just took the active node into account. However, clicking in empty space does not make the active node inactive. Therefore, sometimes clicking on empty space would sometimes remove enter the last selected group node. Furthermore, double clicking on other nodes may also trigger exiting the current group. This is fixed by introducing a new operator that explicitly checks what node is hovered. Pull Request: https://projects.blender.org/blender/blender/pulls/147053 --- .../keyconfig/keymap_data/blender_default.py | 3 +- .../blender/editors/space_node/node_group.cc | 44 +++++++++++++++++++ .../blender/editors/space_node/node_intern.hh | 2 + source/blender/editors/space_node/node_ops.cc | 1 + .../blender/editors/space_node/node_select.cc | 6 +-- 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index c94f119714e..e403f68ec05 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -2268,8 +2268,7 @@ def km_node_editor(params): ("node.group_make", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), ("node.group_ungroup", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None), ("node.group_separate", {"type": 'P', "value": 'PRESS'}, None), - ("node.group_edit", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, - {"properties": [("exit", False)]}), + ("node.group_enter_exit", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), ("node.group_edit", {"type": 'TAB', "value": 'PRESS'}, {"properties": [("exit", False)]}), ("node.group_edit", {"type": 'TAB', "value": 'PRESS', "ctrl": True}, diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index bbae8ecdb6f..1ea1fe0cc2c 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -220,6 +220,50 @@ void NODE_OT_group_edit(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Enter group at cursor, or exit when not hovering any node. + * \{ */ + +static wmOperatorStatus node_group_enter_exit_invoke(bContext *C, + wmOperator * /*op*/, + const wmEvent *event) +{ + SpaceNode &snode = *CTX_wm_space_node(C); + ARegion ®ion = *CTX_wm_region(C); + + float2 cursor; + UI_view2d_region_to_view(®ion.v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y); + bNode *node = node_under_mouse_get(snode, cursor); + + if (!node || node->is_frame()) { + ED_node_tree_pop(®ion, &snode); + return OPERATOR_FINISHED; + } + if (!node->is_group()) { + return OPERATOR_PASS_THROUGH; + } + bNodeTree *group = id_cast(node->id); + if (!group || ID_MISSING(group)) { + return OPERATOR_PASS_THROUGH; + } + ED_node_tree_push(®ion, &snode, group, node); + return OPERATOR_FINISHED; +} + +void NODE_OT_group_enter_exit(wmOperatorType *ot) +{ + ot->name = "Enter/Exit Group"; + ot->description = "Enter or exit node group based on cursor location"; + ot->idname = "NODE_OT_group_enter_exit"; + + ot->invoke = node_group_enter_exit_invoke; + ot->poll = node_group_operator_active_poll; + + ot->flag = OPTYPE_REGISTER; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Ungroup Operator * \{ */ diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 3cef95d05c1..bb1c16ce5bf 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -201,6 +201,7 @@ void node_keymap(wmKeyConfig *keyconf); rctf node_frame_rect_inside(const SpaceNode &snode, const bNode &node); bool node_or_socket_isect_event(const bContext &C, const wmEvent &event); +bNode *node_under_mouse_get(const SpaceNode &snode, const float2 mouse); bool node_deselect_all(bNodeTree &node_tree); void node_socket_select(bNode *node, bNodeSocket &sock); @@ -322,6 +323,7 @@ void NODE_OT_group_insert(wmOperatorType *ot); void NODE_OT_group_ungroup(wmOperatorType *ot); void NODE_OT_group_separate(wmOperatorType *ot); void NODE_OT_group_edit(wmOperatorType *ot); +void NODE_OT_group_enter_exit(wmOperatorType *ot); void NODE_OT_default_group_width_set(wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index de817be1271..db2690b12e0 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -65,6 +65,7 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_group_ungroup); WM_operatortype_append(NODE_OT_group_separate); WM_operatortype_append(NODE_OT_group_edit); + WM_operatortype_append(NODE_OT_group_enter_exit); WM_operatortype_append(NODE_OT_default_group_width_set); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index bac1771e84a..f57372ee170 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -135,7 +135,7 @@ static bool node_frame_select_isect_mouse(const SpaceNode &snode, return false; } -static bNode *node_under_mouse_select(const SpaceNode &snode, const float2 mouse) +bNode *node_under_mouse_get(const SpaceNode &snode, const float2 mouse) { for (bNode *node : tree_draw_order_calc_nodes_reversed(*snode.edittree)) { switch (node->type_legacy) { @@ -158,7 +158,7 @@ static bNode *node_under_mouse_select(const SpaceNode &snode, const float2 mouse static bool is_position_over_node_or_socket(SpaceNode &snode, ARegion ®ion, const float2 &mouse) { - if (node_under_mouse_select(snode, mouse)) { + if (node_under_mouse_get(snode, mouse)) { return true; } if (node_find_indicated_socket(snode, region, mouse, SOCK_IN | SOCK_OUT)) { @@ -606,7 +606,7 @@ static bool node_mouse_select(bContext *C, if (!sock) { /* Find the closest visible node. */ - node = node_under_mouse_select(snode, cursor); + node = node_under_mouse_get(snode, cursor); found = (node != nullptr); node_was_selected = node && (node->flag & SELECT);