Nodes: implement operator node.activate_viewer()

The goal is to have a clear separation between active nodes and active viewers in a node tree. Both the compositor and geometry nodes viewers are supported. This will also allow us to implement shortcuts for viewers for geometry nodes.

A viewer node can be activated using
```
viewer_node = bpy.context.scene.node_tree.nodes["Viewer"]
with bpy.context.temp_override(node=viewer_node):
    bpy.ops.node.activate_viewer()
```

Pull Request: https://projects.blender.org/blender/blender/pulls/134456
This commit is contained in:
Habib Gahbiche
2025-03-07 11:48:45 +01:00
parent 5597e01aa6
commit 6542c86ff5
3 changed files with 58 additions and 0 deletions

View File

@@ -1804,6 +1804,62 @@ void NODE_OT_preview_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int node_activate_viewer_exec(bContext *C, wmOperator * /*op*/)
{
SpaceNode *snode = CTX_wm_space_node(C);
PointerRNA ptr = CTX_data_pointer_get(C, "node");
Main *bmain = CTX_data_main(C);
bNodeTree *ntree = nullptr;
bNode *node = nullptr;
if (ptr.data) {
node = static_cast<bNode *>(ptr.data);
ntree = reinterpret_cast<bNodeTree *>(ptr.owner_id);
}
else if (snode && snode->edittree) {
ntree = snode->edittree;
node = bke::node_get_active(*ntree);
}
if (!node) {
return OPERATOR_CANCELLED;
}
if (node->is_type("CompositorNodeViewer")) {
for (bNode *other_node : ntree->all_nodes()) {
if (other_node->type_legacy == node->type_legacy) {
other_node->flag &= ~NODE_DO_OUTPUT;
}
node->flag |= NODE_DO_OUTPUT;
WM_main_add_notifier(NC_NODE | NA_EDITED, &ntree->id);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
}
}
else if (node->is_type("GeometryNodeViewer")) {
/* Geometry nodes viewers don't rely on NODE_DO_OUTPUT flag alone. */
viewer_path::activate_geometry_node(*bmain, *snode, *node);
}
else {
return OPERATOR_CANCELLED;
}
BKE_main_ensure_invariants(*bmain, snode->edittree->id);
return OPERATOR_FINISHED;
}
void NODE_OT_activate_viewer(wmOperatorType *ot)
{
ot->name = "Activate Viewer Node";
ot->description = "Activate selected viewer node in compositor and geometry nodes";
ot->idname = "NODE_OT_activate_viewer";
ot->exec = node_activate_viewer_exec;
ot->poll = ED_operator_node_active;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int node_deactivate_viewer_exec(bContext *C, wmOperator * /*op*/)
{
SpaceNode &snode = *CTX_wm_space_node(C);

View File

@@ -374,6 +374,7 @@ void NODE_OT_preview_toggle(wmOperatorType *ot);
void NODE_OT_options_toggle(wmOperatorType *ot);
void NODE_OT_node_copy_color(wmOperatorType *ot);
void NODE_OT_deactivate_viewer(wmOperatorType *ot);
void NODE_OT_activate_viewer(wmOperatorType *ot);
void NODE_OT_read_viewlayers(wmOperatorType *ot);
void NODE_OT_render_changed(wmOperatorType *ot);

View File

@@ -44,6 +44,7 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_hide_socket_toggle);
WM_operatortype_append(NODE_OT_node_copy_color);
WM_operatortype_append(NODE_OT_deactivate_viewer);
WM_operatortype_append(NODE_OT_activate_viewer);
WM_operatortype_append(NODE_OT_duplicate);
WM_operatortype_append(NODE_OT_delete);