49#include "RNA_prototypes.hh"
139 if (node &&
STREQ(node->idname, node_idname)) {
150 for (
bNode *dst_node : nodes) {
154 if (output_node_id == 0) {
157 output_node_id = identifier_map.
lookup_default(output_node_id, 0);
158 if (output_node_id == 0) {
181 if (gnode && !exit) {
230 sizeof(*basepath_change),
AT);
233 return basepath_change;
254 const bNestedNodeRef *child_ref = ngroup.find_nested_node_ref(ref.path.id_in_node);
258 constexpr int32_t missing_id = -1;
261 if (new_node_id == missing_id) {
264 ref.path.node_id = new_node_id;
274 ListBase anim_basepaths = {
nullptr,
nullptr};
295 nodes_delayed_free.
append(node);
300 std::optional<std::string> old_animation_basepath;
309 const int32_t old_identifier = node->identifier;
312 node_identifier_map.
add(old_identifier, node->identifier);
324 node->locx += gnode->
locx;
325 node->locy += gnode->
locy;
330 wgroup->
runtime->nodes_by_id.clear();
350 BLI_assert_msg(assign_ok,
"assigning a copy of an already-assigned Action should work");
364 BLI_assert_msg(unassign_ok,
"unassigning an Action that was just assigned should work");
378 if (glinks_first !=
nullptr) {
381 const char *identifier = link->fromsock->identifier;
382 int num_external_links = 0;
388 if (tlink->tonode == gnode &&
STREQ(tlink->tosock->identifier, identifier)) {
390 ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
391 num_external_links++;
397 if (num_external_links == 0) {
404 ntree, link->tosock->new_sock, link->tonode->new_node, ntree, sock, gnode);
417 if (link->fromnode == gnode) {
418 const char *identifier = link->fromsock->identifier;
419 int num_internal_links = 0;
427 if (
STREQ(tlink->tosock->identifier, identifier)) {
429 ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
430 num_internal_links++;
437 if (num_internal_links == 0) {
443 nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode);
450 for (
bNode *node : nodes_delayed_free) {
471 if (
STREQ(node->idname, node_idname)) {
472 if (node->id !=
nullptr) {
473 nodes_to_ungroup.
append(node);
481 for (
bNode *node : nodes_to_ungroup) {
493 ot->
idname =
"NODE_OT_group_ungroup";
517 ListBase anim_basepaths = {
nullptr,
nullptr};
526 [](
const bNode *node) {
return node->is_group_input() || node->is_group_output(); });
528 for (
bNode *node : nodes_to_move) {
532 node_identifier_map.
add(node->identifier, newnode->
identifier);
538 const int32_t old_identifier = node->identifier;
541 node_identifier_map.
add(old_identifier, newnode->
identifier);
543 node_map.
add_new(node, newnode);
560 newnode->
locx += offset.x;
561 newnode->
locy += offset.y;
570 const bool fromselect = (link->fromnode && nodes_to_move.
contains(link->fromnode));
571 const bool toselect = (link->tonode && nodes_to_move.
contains(link->tonode));
575 if (fromselect && toselect) {
577 node_map.
lookup(link->fromnode),
578 socket_map.
lookup(link->fromsock),
579 node_map.
lookup(link->tonode),
580 socket_map.
lookup(link->tosock));
585 if (fromselect && toselect) {
589 else if (fromselect || toselect) {
628 {
NODE_GS_COPY,
"COPY", 0,
"Copy",
"Copy to parent node tree, keep group intact"},
629 {
NODE_GS_MOVE,
"MOVE", 0,
"Move",
"Move to parent node tree, remove from group"},
630 {0,
nullptr, 0,
nullptr,
nullptr},
693 ot->
description =
"Separate selected nodes from the node group";
694 ot->
idname =
"NODE_OT_group_separate";
717 [](
bNode *node) {
return node->is_group_input() || node->is_group_output(); });
718 nodes_to_group.
remove(group_node);
719 return nodes_to_group;
724 const char *ntree_idname,
738 for (
bNode *node : nodes_to_group) {
739 const char *disabled_hint =
nullptr;
740 if (node->typeinfo->poll_instance &&
741 !node->typeinfo->poll_instance(node, ngroup, &disabled_hint))
746 "Cannot add node '%s' in a group:\n %s",
759 ntree.ensure_topology_cache();
760 for (
bNode *node : ntree.all_nodes()) {
761 if (nodes_to_group.
contains(node)) {
766 for (
const bNodeSocket *other_socket : socket->directly_linked_sockets()) {
767 if (nodes_to_group.
contains(
const_cast<bNode *
>(&other_socket->owner_node()))) {
774 if (sockets_connected_to_group(node->input_sockets()) &&
775 sockets_connected_to_group(node->output_sockets()))
783 for (
bNode *input_node : ntree.nodes_by_type(zone_type->input_idname)) {
784 if (
bNode *output_node = zone_type->get_corresponding_output(ntree, *input_node)) {
785 const bool input_selected = nodes_to_group.
contains(input_node);
786 const bool output_selected = nodes_to_group.
contains(output_node);
787 if (input_selected && !output_selected) {
790 "Cannot add zone input node '%s' to a group without its paired output '%s'",
795 if (output_selected && !input_selected) {
798 "Cannot add zone output node '%s' to a group without its paired input '%s'",
815 if (nodes.is_empty()) {
822 for (
const bNode *node : nodes) {
823 const float2 node_offset = {node->offsetx, node->offsety};
827 loc.x += node->width;
828 loc.y -= node->height;
843 if (
node_tree.has_available_link_cycle()) {
846 const bNode &node = socket.owner_node();
847 if (!node.is_reroute()) {
851 node.input_socket(0);
852 if (!other_socket.is_logically_linked()) {
855 return *other_socket.logically_linked_sockets().first();
864 return node.is_group() || node.is_group_input() || node.is_group_output();
873 const bNode &node_for_io = socket_for_io.owner_node();
878 tree_for_interface, node_for_io, socket_for_io, socket_for_io.
idname, socket_for_name.
name);
892 new_nested_node_refs.
append(ref);
896 used_nested_node_ref_ids.
add(ref.id);
901 if (new_node_id == -1) {
910 if (used_nested_node_ref_ids.
add(new_id)) {
915 new_id_by_old_path.
add_new(ref.path, new_ref.
id);
916 new_nested_node_refs.
append(new_ref);
920 ref.path.id_in_node = new_ref.
id;
926 new_nested_node_refs.
data(), new_nested_node_refs.
size(), group.nested_node_refs);
927 group.nested_node_refs_num = new_nested_node_refs.
size();
945 float2 real_min, real_max;
949 const bool expose_visible = nodes_to_move.
size() == 1;
952 group.ensure_topology_cache();
953 bNode *output_node = [&]() {
954 if (
bNode *node = group.group_output_node()) {
958 output_node->
locx = real_max[0] - center[0] + 50.0f;
964 input_node->
locx = real_min[0] - center[0] - 200.0f;
966 struct InputSocketInfo {
974 struct OutputLinkInfo {
979 struct NewInternalLinkInfo {
994 ntree.ensure_topology_cache();
996 for (
bNode *node : nodes_to_move) {
997 for (
bNodeSocket *output_socket : node->output_sockets()) {
998 if (!output_socket->is_available() || output_socket->is_hidden()) {
999 for (
bNodeLink *link : output_socket->directly_linked_links()) {
1000 links_to_remove.
add(link);
1005 for (
bNodeLink *link : output_socket->directly_linked_links()) {
1007 links_to_remove.
add(link);
1010 if (link->tonode == gnode) {
1011 links_to_remove.
add(link);
1014 if (nodes_to_move.
contains(link->tonode)) {
1015 internal_links_to_move.
add(link);
1019 ntree, group, *link->fromsock);
1021 output_links.
append({link, io_socket});
1024 links_to_remove.
add(link);
1027 if (expose_visible && !output_socket->is_directly_linked()) {
1029 group, *node, *output_socket);
1031 new_internal_links.
append({
node, output_socket, io_socket});
1037 for (
bNode *node : nodes_to_move) {
1038 for (
bNodeSocket *input_socket : node->input_sockets()) {
1039 if (!input_socket->is_available() || input_socket->is_hidden()) {
1040 for (
bNodeLink *link : input_socket->directly_linked_links()) {
1041 links_to_remove.
add(link);
1046 for (
bNodeLink *link : input_socket->directly_linked_links()) {
1048 links_to_remove.
add(link);
1051 if (link->fromnode == gnode) {
1052 links_to_remove.
add(link);
1055 if (nodes_to_move.
contains(link->fromnode)) {
1056 internal_links_to_move.
add(link);
1060 info.from_node = link->fromnode;
1061 info.links.append(link);
1062 if (!info.interface_socket) {
1066 if (expose_visible && !input_socket->is_directly_linked()) {
1068 group, *node, *input_socket);
1070 new_internal_links.
append({
node, input_socket, io_socket});
1077 for (
bNode *node : ntree.all_nodes()) {
1078 if (node->parent && nodes_to_move.
contains(node->parent) && !nodes_to_move.
contains(node)) {
1082 for (
bNode *node : nodes_to_move) {
1083 if (node->parent && !nodes_to_move.
contains(node->parent)) {
1090 ListBase anim_basepaths = {
nullptr,
nullptr};
1091 for (
bNode *node : nodes_to_move) {
1105 for (
bNode *node : nodes_to_move) {
1106 const int32_t old_identifier = node->identifier;
1113 node_identifier_map.
add(old_identifier, node->identifier);
1125 for (
bNode *node : nodes_to_move) {
1126 if (!node->parent) {
1127 node->locx -= center[0];
1128 node->locy -= center[1];
1132 for (
bNodeLink *link : internal_links_to_move) {
1139 for (
bNodeLink *link : links_to_remove) {
1144 for (
const auto item : input_links.
items()) {
1145 const StringRefNull interface_identifier = item.value.interface_socket->identifier;
1147 interface_identifier.
c_str());
1149 for (
bNodeLink *link : item.value.links) {
1155 link->fromnode = input_node;
1156 link->fromsock = input_socket;
1161 for (
const OutputLinkInfo &info : output_links) {
1163 const StringRefNull io_identifier = info.interface_socket->identifier;
1165 bke::node_add_link(&group, info.link->fromnode, info.link->fromsock, output_node, output_sock);
1169 for (
const NewInternalLinkInfo &info : new_internal_links) {
1170 const StringRefNull io_identifier = info.interface_socket->identifier;
1171 if (info.socket->in_out ==
SOCK_IN) {
1177 io_identifier.
c_str());
1190 for (
const auto item : input_links.
items()) {
1191 const StringRefNull interface_identifier = item.value.interface_socket->identifier;
1193 interface_identifier.
c_str());
1194 bke::node_add_link(&ntree, item.value.from_node, item.key, gnode, group_node_socket);
1198 for (
const OutputLinkInfo &info : output_links) {
1200 info.link->fromnode = gnode;
1213 const char *ntreetype)
1227 gnode->
id = (
ID *)ngroup;
1229 gnode->
locx = 0.5f * (
min[0] + max[0]);
1230 gnode->
locy = 0.5f * (
min[1] + max[1]);
1301 if (!gnode || !gnode->
id) {
1309 for (
const bNode *group : nodes_to_group) {
1310 if (!group->is_group() || group->id ==
nullptr) {
1335 ot->
name =
"Group Insert";
1336 ot->
description =
"Insert selected nodes into a node group";
1337 ot->
idname =
"NODE_OT_group_insert";
1381 if (!parent_path_item) {
1385 if (!parent_ntree) {
1388 parent_ntree->ensure_topology_cache();
1401 ot->
name =
"Set Default Group Node Width";
1402 ot->
description =
"Set the width based on the parent group node in the current context";
1403 ot->
idname =
"NODE_OT_default_group_width_set";
Functions and classes to work with Actions.
Blender kernel action and pose functionality.
void BKE_animdata_transfer_by_basepath(struct Main *bmain, struct ID *srcID, struct ID *dstID, struct ListBase *basepaths)
SpaceNode * CTX_wm_space_node(const bContext *C)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_id_free(Main *bmain, void *idv)
void BKE_id_move_to_same_lib(Main &bmain, ID &id, const ID &owner_id)
ID * BKE_id_copy(Main *bmain, const ID *id)
#define NODE_GROUP_OUTPUT
void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_all(bNodeTree *ntree)
void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *link)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_msg(a, msg)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
#define BLI_SCOPED_DEFER(function_to_defer)
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define INIT_MINMAX2(min, max)
#define UNUSED_VARS_NDEBUG(...)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
void DEG_relations_tag_update(Main *bmain)
#define ID_IS_EDITABLE(_id)
void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *ntree)
bNodeTree * ED_node_tree_get(SpaceNode *snode, int level)
bool ED_node_is_compositor(const SpaceNode *snode)
void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
bool ED_node_is_shader(SpaceNode *snode)
void ED_node_tree_pop(SpaceNode *snode)
bool ED_node_is_geometry(SpaceNode *snode)
bool ED_node_is_texture(SpaceNode *snode)
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
bool ED_operator_node_editable(bContext *C)
bool ED_operator_node_active(bContext *C)
Read Guarded memory(de)allocation.
struct blender::bke::bNodeTreeType * ntreeType_Shader
struct blender::bke::bNodeTreeType * ntreeType_Texture
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
Value & lookup_or_add_default(const Key &key)
bool add(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
Value lookup_default(const Key &key, const Value &default_value) const
ValueIterator values() const
void add_new(const Key &key, const Value &value)
ItemIterator items() const
static RandomNumberGenerator from_random_seed()
constexpr bool contains(const T &value) const
constexpr int64_t size() const
constexpr const char * data() const
constexpr const char * c_str() const
bool contains(const Key &key) const
bool remove(const Key &key)
int64_t remove_if(Predicate &&predicate)
void append(const T &value)
virtual const int & get_corresponding_output_id(const bNode &input_bnode) const =0
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
bool unassign_action(ID &animated_id)
bool assign_action(bAction *action, ID &animated_id)
bool update_field_inferencing(const bNodeTree &tree)
bNodeTreeInterfaceSocket * add_interface_socket_from_node(bNodeTree &ntree, const bNode &from_node, const bNodeSocket &from_sock, const StringRef socket_type, const StringRef name)
const bNodeZoneType * zone_type_by_node_type(const int node_type)
float2 node_to_view(const bNode *node, float2 loc)
void node_set_active(bNodeTree *ntree, bNode *node)
void node_detach_node(bNodeTree *ntree, bNode *node)
bool node_link_is_hidden(const bNodeLink *link)
bNodeTree * node_tree_copy_tree(Main *bmain, const bNodeTree *ntree)
bNode * node_add_static_node(const bContext *C, bNodeTree *ntree, int type)
void node_remove_node(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
bNode * node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, int flag, bool use_unique, Map< const bNodeSocket *, bNodeSocket * > &new_socket_map)
bNodeLink * node_add_link(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
bNodeTree * node_tree_add_tree(Main *bmain, const char *name, const char *idname)
bNode * node_get_active(bNodeTree *ntree)
bNode * node_add_node(const bContext *C, bNodeTree *ntree, const char *idname)
void node_rebuild_id_vector(bNodeTree *node_tree)
void node_remove_link(bNodeTree *ntree, bNodeLink *link)
void node_tree_free_tree(bNodeTree *ntree)
Span< const bNodeZoneType * > all_zone_types()
Span< int > all_zone_input_node_types()
bool node_tree_contains_tree(const bNodeTree *tree_to_search_in, const bNodeTree *tree_to_search_for)
bool node_declaration_ensure(bNodeTree *ntree, bNode *node)
void node_unique_id(bNodeTree *ntree, bNode *node)
bNode * node_find_node_by_name(bNodeTree *ntree, const char *name)
void node_unique_name(bNodeTree *ntree, bNode *node)
static bool node_group_make_test_selected(bNodeTree &ntree, const VectorSet< bNode * > &nodes_to_group, const char *ntree_idname, ReportList &reports)
static bool node_default_group_width_set_poll(bContext *C)
static int node_group_make_exec(bContext *C, wmOperator *op)
static bool prefer_node_for_interface_name(const bNode &node)
static bool node_group_operator_active_poll(bContext *C)
static bNodeTreeInterfaceSocket * add_interface_from_socket(const bNodeTree &original_tree, bNodeTree &tree_for_interface, const bNodeSocket &socket)
static AnimationBasePathChange * animation_basepath_change_new(const StringRef src_basepath, const StringRef dst_basepath)
static VectorSet< bNode * > get_nodes_to_group(bNodeTree &node_tree, bNode *group_node)
static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, bNode *gnode, const VectorSet< bNode * > &nodes_to_move)
static int node_group_insert_exec(bContext *C, wmOperator *op)
static bNode * node_group_get_active(bContext *C, const char *node_idname)
static int node_group_separate_invoke(bContext *C, wmOperator *, const wmEvent *)
static const char * group_ntree_idname(bContext *C)
bool node_deselect_all(bNodeTree &node_tree)
static void node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
void NODE_OT_group_make(wmOperatorType *ot)
static void update_nested_node_refs_after_moving_nodes_into_group(bNodeTree &ntree, bNodeTree &group, bNode &gnode, const Map< int32_t, int32_t > &node_identifier_map)
static const EnumPropertyItem node_group_separate_types[]
void NODE_OT_group_insert(wmOperatorType *ot)
static int node_group_ungroup_exec(bContext *C, wmOperator *)
static bool node_group_separate_selected(Main &bmain, bNodeTree &ntree, bNodeTree &ngroup, const float2 &offset, const bool make_copy)
static int node_group_edit_exec(bContext *C, wmOperator *op)
static int node_default_group_width_set_exec(bContext *C, wmOperator *)
static const bNodeSocket & find_socket_to_use_for_interface(const bNodeTree &node_tree, const bNodeSocket &socket)
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
const char * node_group_idname(bContext *C)
static bool node_group_operator_editable(bContext *C)
float2 space_node_group_offset(const SpaceNode &snode)
static void get_min_max_of_nodes(const Span< bNode * > nodes, const bool use_size, float2 &min, float2 &max)
void NODE_OT_group_edit(wmOperatorType *ot)
static void update_nested_node_refs_after_ungroup(bNodeTree &ntree, const bNodeTree &ngroup, const bNode &gnode, const Map< int32_t, int32_t > &node_identifier_map)
void NODE_OT_group_separate(wmOperatorType *ot)
static int node_group_separate_exec(bContext *C, wmOperator *op)
static void remap_pairing(bNodeTree &dst_tree, Span< bNode * > nodes, const Map< int32_t, int32_t > &identifier_map)
void NODE_OT_default_group_width_set(wmOperatorType *ot)
void NODE_OT_group_ungroup(wmOperatorType *ot)
static bNode * node_group_make_from_nodes(const bContext &C, bNodeTree &ntree, const VectorSet< bNode * > &nodes_to_group, const char *ntype, const char *ntreetype)
static void animation_basepath_change_free(AnimationBasePathChange *basepath_change)
T midpoint(const T &a, const T &b)
void min_max(const T &value, T &min, T &max)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
VecBase< float, 2 > float2
void uninitialized_copy_n(const T *src, int64_t n, T *dst)
bNodeSocket * node_group_input_find_socket(bNode *node, const char *identifier)
bNodeSocket * node_group_find_output_socket(bNode *groupnode, const char *identifier)
bNodeSocket * node_group_output_find_socket(bNode *node, const char *identifier)
bNodeSocket * node_group_find_input_socket(bNode *groupnode, const char *identifier)
blender::bke::bNodeTreeType * ntreeType_Composite
blender::bke::bNodeTreeType * ntreeType_Geometry
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
std::optional< std::string > RNA_path_from_ID_to_struct(const PointerRNA *ptr)
const char * dst_basepath
const char * src_basepath
struct bNodeTree * edittree
struct bNodeTree * nodetree
struct bNodeTree * nodetree
struct bNodeTreePath * prev
bNodeTreeRuntimeHandle * runtime
int default_group_node_width
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
struct ReportList * reports
void WM_event_add_notifier(const bContext *C, uint type, void *reference)