Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_templates.cc
| Show All 14 Lines | |||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup edinterface | * \ingroup edinterface | ||||
| */ | */ | ||||
| #include <cstdlib> | #include <cstdlib> | ||||
| #include <cstring> | #include <cstring> | ||||
| #include <optional> | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DNA_node_types.h" | #include "DNA_node_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "BLI_array.h" | #include "BLI_array.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_lib_id.h" | #include "BKE_lib_id.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "NOD_node_declaration.hh" | |||||
| #include "NOD_socket.h" | #include "NOD_socket.h" | ||||
| #include "NOD_socket_declarations.hh" | |||||
| #include "../interface/interface_intern.h" /* XXX bad level */ | #include "../interface/interface_intern.h" /* XXX bad level */ | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "ED_node.h" /* own include */ | #include "ED_node.h" /* own include */ | ||||
| #include "node_intern.h" | #include "node_intern.h" | ||||
| #include "ED_undo.h" | #include "ED_undo.h" | ||||
| using blender::Vector; | |||||
| using blender::nodes::NodeDeclaration; | |||||
| /************************* Node Socket Manipulation **************************/ | /************************* Node Socket Manipulation **************************/ | ||||
| /* describes an instance of a node type and a specific socket to link */ | /* describes an instance of a node type and a specific socket to link */ | ||||
| struct NodeLinkItem { | struct NodeLinkItem { | ||||
| int socket_index; /* index for linking */ | int socket_index = -1; /* index for linking */ | ||||
| int socket_type; /* socket type for compatibility check */ | int socket_type = SOCK_CUSTOM; /* socket type for compatibility check */ | ||||
| const char *socket_name; /* ui label of the socket */ | const char *socket_name = nullptr; /* ui label of the socket */ | ||||
| const char *node_name; /* ui label of the node */ | const char *node_name = nullptr; /* ui label of the node */ | ||||
| /* extra settings */ | /* extra settings */ | ||||
| bNodeTree *ngroup; /* group node tree */ | bNodeTree *ngroup = nullptr; /* group node tree */ | ||||
| }; | }; | ||||
| /* Compare an existing node to a link item to see if it can be reused. | /* Compare an existing node to a link item to see if it can be reused. | ||||
| * item must be for the same node type! | * item must be for the same node type! | ||||
| * XXX should become a node type callback | * XXX should become a node type callback | ||||
| */ | */ | ||||
| static bool node_link_item_compare(bNode *node, NodeLinkItem *item) | static bool node_link_item_compare(bNode *node, NodeLinkItem *item) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 243 Lines • ▼ Show 20 Lines | struct NodeLinkArg { | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| bNodeType *node_type; | bNodeType *node_type; | ||||
| NodeLinkItem item; | NodeLinkItem item; | ||||
| uiLayout *layout; | uiLayout *layout; | ||||
| }; | }; | ||||
| static void ui_node_link_items(NodeLinkArg *arg, | static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg, | ||||
| int in_out, | int in_out, | ||||
| NodeLinkItem **r_items, | std::optional<NodeDeclaration> &r_node_decl) | ||||
| int *r_totitems) | |||||
| { | { | ||||
| /* XXX this should become a callback for node types! */ | Vector<NodeLinkItem> items; | ||||
| NodeLinkItem *items = nullptr; | |||||
| int totitems = 0; | |||||
| /* XXX this should become a callback for node types! */ | |||||
| if (arg->node_type->type == NODE_GROUP) { | if (arg->node_type->type == NODE_GROUP) { | ||||
| bNodeTree *ngroup; | bNodeTree *ngroup; | ||||
| int i; | int i; | ||||
| for (ngroup = (bNodeTree *)arg->bmain->nodetrees.first; ngroup; | for (ngroup = (bNodeTree *)arg->bmain->nodetrees.first; ngroup; | ||||
| ngroup = (bNodeTree *)ngroup->id.next) { | ngroup = (bNodeTree *)ngroup->id.next) { | ||||
| const char *disabled_hint; | const char *disabled_hint; | ||||
| if ((ngroup->type != arg->ntree->type) || | if ((ngroup->type != arg->ntree->type) || | ||||
| !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) { | !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs); | |||||
| totitems += BLI_listbase_count(lb); | |||||
| } | } | ||||
| if (totitems > 0) { | |||||
| items = (NodeLinkItem *)MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items"); | |||||
| i = 0; | i = 0; | ||||
| for (ngroup = (bNodeTree *)arg->bmain->nodetrees.first; ngroup; | for (ngroup = (bNodeTree *)arg->bmain->nodetrees.first; ngroup; | ||||
| ngroup = (bNodeTree *)ngroup->id.next) { | ngroup = (bNodeTree *)ngroup->id.next) { | ||||
| const char *disabled_hint; | const char *disabled_hint; | ||||
| if ((ngroup->type != arg->ntree->type) || | if ((ngroup->type != arg->ntree->type) || | ||||
| !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) { | !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs); | ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs); | ||||
| bNodeSocket *stemp; | bNodeSocket *stemp; | ||||
| int index; | int index; | ||||
| for (stemp = (bNodeSocket *)lb->first, index = 0; stemp; | for (stemp = (bNodeSocket *)lb->first, index = 0; stemp; stemp = stemp->next, index++, i++) { | ||||
| stemp = stemp->next, index++, i++) { | NodeLinkItem item; | ||||
| NodeLinkItem *item = &items[i]; | item.socket_index = index; | ||||
| item->socket_index = index; | |||||
| /* NOTE: int stemp->type is not fully reliable, not used for node group | /* NOTE: int stemp->type is not fully reliable, not used for node group | ||||
| * interface sockets. use the typeinfo->type instead. | * interface sockets. use the typeinfo->type instead. | ||||
| */ | */ | ||||
| item->socket_type = stemp->typeinfo->type; | item.socket_type = stemp->typeinfo->type; | ||||
| item->socket_name = stemp->name; | item.socket_name = stemp->name; | ||||
| item->node_name = ngroup->id.name + 2; | item.node_name = ngroup->id.name + 2; | ||||
| item->ngroup = ngroup; | item.ngroup = ngroup; | ||||
| items.append(item); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (arg->node_type->declare != nullptr) { | |||||
| using namespace blender; | |||||
| using namespace blender::nodes; | |||||
| r_node_decl.emplace(NodeDeclaration()); | |||||
| NodeDeclarationBuilder node_decl_builder{*r_node_decl}; | |||||
| arg->node_type->declare(node_decl_builder); | |||||
| Span<SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? r_node_decl->inputs() : | |||||
| r_node_decl->outputs(); | |||||
| int index = 0; | |||||
| for (const SocketDeclarationPtr &socket_decl_ptr : socket_decls) { | |||||
| const SocketDeclaration &socket_decl = *socket_decl_ptr; | |||||
| NodeLinkItem item; | |||||
| item.socket_index = index++; | |||||
| /* A socket declaration does not necessarily map to exactly one built-in socket type. So only | |||||
| * check for the types that matter here. */ | |||||
| if (dynamic_cast<const decl::Color *>(&socket_decl)) { | |||||
| item.socket_type = SOCK_RGBA; | |||||
| } | } | ||||
| else if (dynamic_cast<const decl::Float *>(&socket_decl)) { | |||||
| item.socket_type = SOCK_FLOAT; | |||||
| } | } | ||||
| else if (dynamic_cast<const decl::Vector *>(&socket_decl)) { | |||||
| item.socket_type = SOCK_VECTOR; | |||||
| } | |||||
| else { | |||||
| item.socket_type = SOCK_CUSTOM; | |||||
| } | |||||
| item.socket_name = socket_decl.name().c_str(); | |||||
| item.node_name = arg->node_type->ui_name; | |||||
| items.append(item); | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs : | bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs : | ||||
| arg->node_type->outputs); | arg->node_type->outputs); | ||||
| bNodeSocketTemplate *stemp; | bNodeSocketTemplate *stemp; | ||||
| int i; | int i; | ||||
| for (stemp = socket_templates; stemp && stemp->type != -1; stemp++) { | |||||
| totitems++; | |||||
| } | |||||
| if (totitems > 0) { | |||||
| items = (NodeLinkItem *)MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items"); | |||||
| i = 0; | i = 0; | ||||
| for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) { | for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) { | ||||
| NodeLinkItem *item = &items[i]; | NodeLinkItem item; | ||||
| item.socket_index = i; | |||||
| item->socket_index = i; | item.socket_type = stemp->type; | ||||
| item->socket_type = stemp->type; | item.socket_name = stemp->name; | ||||
| item->socket_name = stemp->name; | item.node_name = arg->node_type->ui_name; | ||||
| item->node_name = arg->node_type->ui_name; | items.append(item); | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| *r_items = items; | return items; | ||||
| *r_totitems = totitems; | |||||
| } | } | ||||
| static void ui_node_link(bContext *C, void *arg_p, void *event_p) | static void ui_node_link(bContext *C, void *arg_p, void *event_p) | ||||
| { | { | ||||
| NodeLinkArg *arg = (NodeLinkArg *)arg_p; | NodeLinkArg *arg = (NodeLinkArg *)arg_p; | ||||
| Main *bmain = arg->bmain; | Main *bmain = arg->bmain; | ||||
| bNode *node_to = arg->node; | bNode *node_to = arg->node; | ||||
| bNodeSocket *sock_to = arg->sock; | bNodeSocket *sock_to = arg->sock; | ||||
| ▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) | ||||
| NODE_TYPES_END; | NODE_TYPES_END; | ||||
| qsort( | qsort( | ||||
| sorted_ntypes.data(), sorted_ntypes.size(), sizeof(bNodeType *), ui_node_item_name_compare); | sorted_ntypes.data(), sorted_ntypes.size(), sizeof(bNodeType *), ui_node_item_name_compare); | ||||
| /* generate UI */ | /* generate UI */ | ||||
| for (int j = 0; j < sorted_ntypes.size(); j++) { | for (int j = 0; j < sorted_ntypes.size(); j++) { | ||||
| bNodeType *ntype = sorted_ntypes[j]; | bNodeType *ntype = sorted_ntypes[j]; | ||||
| NodeLinkItem *items; | |||||
| int totitems; | |||||
| char name[UI_MAX_NAME_STR]; | char name[UI_MAX_NAME_STR]; | ||||
| const char *cur_node_name = nullptr; | const char *cur_node_name = nullptr; | ||||
| int num = 0; | int num = 0; | ||||
| int icon = ICON_NONE; | int icon = ICON_NONE; | ||||
| arg->node_type = ntype; | arg->node_type = ntype; | ||||
| ui_node_link_items(arg, SOCK_OUT, &items, &totitems); | std::optional<blender::nodes::NodeDeclaration> node_decl; | ||||
| Vector<NodeLinkItem> items = ui_node_link_items(arg, SOCK_OUT, node_decl); | |||||
| for (int i = 0; i < totitems; i++) { | for (const NodeLinkItem &item : items) { | ||||
| if (ui_compatible_sockets(items[i].socket_type, sock->type)) { | if (ui_compatible_sockets(item.socket_type, sock->type)) { | ||||
| num++; | num++; | ||||
| } | } | ||||
| } | } | ||||
| for (int i = 0; i < totitems; i++) { | for (const NodeLinkItem &item : items) { | ||||
| if (!ui_compatible_sockets(items[i].socket_type, sock->type)) { | if (!ui_compatible_sockets(item.socket_type, sock->type)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (first) { | if (first) { | ||||
| column = uiLayoutColumn(layout, false); | column = uiLayoutColumn(layout, false); | ||||
| UI_block_layout_set_current(block, column); | UI_block_layout_set_current(block, column); | ||||
| uiItemL(column, IFACE_(cname), ICON_NODE); | uiItemL(column, IFACE_(cname), ICON_NODE); | ||||
| but = (uiBut *)block->buttons.last; | but = (uiBut *)block->buttons.last; | ||||
| first = 0; | first = 0; | ||||
| } | } | ||||
| if (num > 1) { | if (num > 1) { | ||||
| if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) { | if (!cur_node_name || !STREQ(cur_node_name, item.node_name)) { | ||||
| cur_node_name = items[i].node_name; | cur_node_name = item.node_name; | ||||
| /* XXX Do not use uiItemL here, | /* XXX Do not use uiItemL here, | ||||
| * it would add an empty icon as we are in a menu! */ | * it would add an empty icon as we are in a menu! */ | ||||
| uiDefBut(block, | uiDefBut(block, | ||||
| UI_BTYPE_LABEL, | UI_BTYPE_LABEL, | ||||
| 0, | 0, | ||||
| IFACE_(cur_node_name), | IFACE_(cur_node_name), | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| UI_UNIT_X * 4, | UI_UNIT_X * 4, | ||||
| UI_UNIT_Y, | UI_UNIT_Y, | ||||
| nullptr, | nullptr, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| ""); | ""); | ||||
| } | } | ||||
| BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(items[i].socket_name)); | BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(item.socket_name)); | ||||
| icon = ICON_BLANK1; | icon = ICON_BLANK1; | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_strncpy(name, IFACE_(items[i].node_name), UI_MAX_NAME_STR); | BLI_strncpy(name, IFACE_(item.node_name), UI_MAX_NAME_STR); | ||||
| icon = ICON_NONE; | icon = ICON_NONE; | ||||
| } | } | ||||
| but = uiDefIconTextBut(block, | but = uiDefIconTextBut(block, | ||||
| UI_BTYPE_BUT, | UI_BTYPE_BUT, | ||||
| 0, | 0, | ||||
| icon, | icon, | ||||
| name, | name, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| UI_UNIT_X * 4, | UI_UNIT_X * 4, | ||||
| UI_UNIT_Y, | UI_UNIT_Y, | ||||
| nullptr, | nullptr, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| 0.0, | 0.0, | ||||
| TIP_("Add node to input")); | TIP_("Add node to input")); | ||||
| argN = (NodeLinkArg *)MEM_dupallocN(arg); | argN = (NodeLinkArg *)MEM_dupallocN(arg); | ||||
| argN->item = items[i]; | argN->item = item; | ||||
| UI_but_funcN_set(but, ui_node_link, argN, nullptr); | UI_but_funcN_set(but, ui_node_link, argN, nullptr); | ||||
| } | } | ||||
| if (items) { | |||||
| MEM_freeN(items); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name) | static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name) | ||||
| { | { | ||||
| NodeLinkArg *arg = (NodeLinkArg *)calldata; | NodeLinkArg *arg = (NodeLinkArg *)calldata; | ||||
| if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT)) { | if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT)) { | ||||
| ▲ Show 20 Lines • Show All 290 Lines • Show Last 20 Lines | |||||