38#include "RNA_prototypes.hh"
103 snode.
edittree->ensure_topology_cache();
125 bNode &node = socket->owner_node();
128 const float cursor_link_touch_distance = 12.5f *
UI_SCALE_FAC;
132 for (
bNodeLink *link : socket->directly_linked_links()) {
134 std::array<float2, NODE_LINK_RESOL + 1> coords;
137 for (
const int i :
IndexRange(coords.size() - 1)) {
139 if (
distance < cursor_link_touch_distance) {
151 if (last_picked_link) {
152 link_to_pick = last_picked_link;
162 pick_link(nldrag, *snode, &node, *link_to_pick);
169 ntree->ensure_topology_cache();
170 if (!sock->is_visible()) {
187 const bool allow_multiple)
195 if (sock->flag &
SELECT) {
207 if (sock->type == sock_target->
type) {
208 if (
STREQ(sock->name, sock_target->
name)) {
221 if (sock->type == sock_target->
type) {
228 ntree->ensure_topology_cache();
229 if (
STREQ(sock_target->
idname,
"NodeSocketVirtual")) {
231 if (!
output->is_icon_visible()) {
237 bool is_output_linked_to_target_node =
false;
238 for (
bNodeSocket *socket : directly_linked_sockets) {
239 if (&socket->owner_node() == &sock_target->owner_node()) {
240 is_output_linked_to_target_node =
true;
246 if (is_output_linked_to_target_node) {
256 if (node->is_reroute()) {
269 const bool only_unlinked)
279 return a->type > b->type;
331 for (
bNodeLink *link : socket.directly_linked_links()) {
333 socket_location, link->multi_input_sort_id, link->tosock->runtime->total_inputs);
334 links.
append({link, location});
337 links.
append({&drag_link, cursor});
340 return a.multi_socket_position.y < b.multi_socket_position.y;
344 links[
i].link->multi_input_sort_id =
i;
351 if (!socket->is_multi_input()) {
356 return a->multi_input_sort_id < b->multi_input_sort_id;
360 links[
i]->multi_input_sort_id =
i;
367 const bool allow_multiple,
375 return a->location[0] < b->location[0];
379 for (
const int i : sorted_nodes.
as_mutable_span().drop_back(1).index_range()) {
380 bool has_selected_inputs =
false;
382 bNode *node_fr = sorted_nodes[
i];
383 bNode *node_to = sorted_nodes[
i + 1];
386 std::swap(node_fr, node_to);
391 if (sock_to->flag &
SELECT) {
392 has_selected_inputs =
true;
410 if (!has_selected_inputs) {
439 if (!socket.is_icon_visible()) {
452 if (storage.items_num >= 1) {
458 std::optional<int> existing_geometry_index;
459 for (
const int i :
IndexRange(storage.items_num)) {
462 existing_geometry_index =
i;
466 if (existing_geometry_index) {
480 if (storage.items_num == 0) {
482 ntree, viewer_node, socket_type,
IFACE_(
"Value"));
485 if (storage.items_num == 1 && storage.items[0].socket_type !=
SOCK_GEOMETRY) {
486 storage.items[0].socket_type = socket_type;
489 if (storage.items_num == 1 && storage.items[0].socket_type ==
SOCK_GEOMETRY) {
491 ntree, viewer_node, socket_type,
IFACE_(
"Value"));
494 if (storage.items_num == 2 && storage.items[0].socket_type ==
SOCK_GEOMETRY &&
497 storage.items[1].socket_type = socket_type;
500 std::optional<int> existing_geometry_index;
501 for (
const int i :
IndexRange(storage.items_num)) {
503 existing_geometry_index =
i;
507 if (existing_geometry_index) {
509 storage.items[1].socket_type = socket_type;
522 const bNode &node = socket.owner_node();
523 if (node.is_reroute()) {
524 const bNodeSocket &reroute_input = node.input_socket(0);
525 if (!reroute_input.is_logically_linked()) {
528 return reroute_input.logically_linked_sockets()[0]->
name;
558 ntree, viewer_node, src_socket.
typeinfo->type);
564 viewer_node, item,
name.c_str());
577 const bNode &node = socket.owner_node();
582 return socket.index() == 0;
602 if (link->tonode == &viewer_node) {
612 int last_linked_data_socket_index = -1;
613 bool has_linked_geometry_socket =
false;
618 for (
bNodeLink *link : socket->directly_linked_links()) {
620 bNode &target_node = *link->tonode;
627 has_linked_geometry_socket =
true;
630 last_linked_data_socket_index = socket->index();
636 if (last_linked_data_socket_index == -1 && !has_linked_geometry_socket) {
649 const int tot_outputs =
node_to_view.output_sockets().size();
650 for (
const int offset :
IndexRange(1, tot_outputs)) {
651 const int index = (last_linked_data_socket_index + offset) % tot_outputs;
658 already_viewed_socket = &output_socket;
662 bool is_currently_viewed =
false;
663 for (
const bNodeLink *link : output_socket.directly_linked_links()) {
665 bNode &target_node = *link->tonode;
669 if (link->is_muted()) {
675 is_currently_viewed =
true;
678 if (is_currently_viewed) {
679 already_viewed_socket = &output_socket;
682 return &output_socket;
684 return already_viewed_socket;
700 std::optional<int> item_identifier;
713 if (node->is_type(
"CompositorNodeViewer") && node != &viewer_node) {
726 for (
const bNode *node :
tree.all_nodes()) {
727 if (node->is_frame()) {
733 if (
BLI_rctf_isect(&rect, &node->runtime->draw_bounds,
nullptr)) {
745 const float step_distance,
746 const float max_distance)
749 const float y_scale = 0.5f;
752 candidates.
append(initial);
755 const int checks = std::max<int>(2,
ceilf(
arc_length / step_distance));
758 const float candidate_x = initial.x +
distance * std::sin(
angle);
759 const float candidate_y = initial.y +
distance * std::cos(
angle) * y_scale;
760 candidates.
append({candidate_x, candidate_y});
780 tree.ensure_topology_cache();
784 region_rect.
xmin = 0;
786 region_rect.
ymin = 0;
799 if (!is_new_viewer_node &&
808 const float default_padding_x =
U.node_margin;
809 const float default_padding_y = 10;
810 const float viewer_width = is_new_viewer_node ?
813 const float viewer_height = is_new_viewer_node ?
817 const float2 main_candidate{
node_to_view.runtime->draw_bounds.xmax + default_padding_x,
818 node_to_view.runtime->draw_bounds.ymax + viewer_height +
821 std::optional<float2> new_viewer_position;
825 for (
const float2 &candidate_pos : position_candidates) {
827 candidate.
xmin = candidate_pos.x;
828 candidate.
xmax = candidate_pos.x + viewer_width;
829 candidate.
ymin = candidate_pos.y - viewer_height;
830 candidate.
ymax = candidate_pos.y;
837 rctf padded_candidate = candidate;
838 BLI_rctf_pad(&padded_candidate, default_padding_x - 1, default_padding_y - 1);
842 if (!overlapping_node) {
843 new_viewer_position = candidate_pos;
848 if (!new_viewer_position) {
849 new_viewer_position = main_candidate;
854 viewer_node.
parent =
nullptr;
860 bNode &bnode_to_view,
863 bNode *viewer_node =
nullptr;
865 for (
bNode *node : btree.all_nodes()) {
875 for (
bNodeLink *link : bsocket_to_view.directly_linked_links()) {
877 bNode &target_node = *link->tonode;
885 if (viewer_node ==
nullptr) {
886 for (
bNode *node : btree.all_nodes()) {
893 if (viewer_node ==
nullptr) {
894 const float2 socket_location = bsocket_to_view.
runtime->location;
902 if (viewer_bsocket ==
nullptr) {
909 if (link->tosock == viewer_bsocket) {
914 if (viewer_link ==
nullptr) {
916 btree, bnode_to_view, bsocket_to_view, *viewer_node, *viewer_bsocket);
919 viewer_link->
fromnode = &bnode_to_view;
920 viewer_link->
fromsock = &bsocket_to_view;
932 btree->ensure_topology_cache();
934 if (bsocket_to_view ==
nullptr) {
938 if (bsocket_to_view ==
nullptr) {
942 return view_socket(
C, snode, *btree, bnode_to_view, *bsocket_to_view);
966 if (socket->flag &
SELECT) {
967 socket_to_view = socket;
1003 ot->name =
"Link to Viewer Node";
1004 ot->description =
"Link to viewer node";
1005 ot->idname =
"NODE_OT_link_viewer";
1094 const int icon = !swap_links ? ICON_ADD : (new_link ? ICON_ANIM : ICON_UV_SYNC_SELECT);
1120 if (
ELEM(&socket, link->fromsock, link->tosock)) {
1136 while (socket != socket_to_match) {
1137 if (socket->is_visible()) {
1138 const bool sockets_are_compatible = socket->
typeinfo == socket_to_match->
typeinfo;
1139 if (sockets_are_compatible) {
1142 if (socket_has_capacity) {
1149 socket = socket->
next ? socket->
next : first_socket;
1161 if (linked_socket->is_input()) {
1162 BLI_assert(!linked_socket->is_multi_input());
1163 ntree->ensure_topology_cache();
1165 if (linked_socket->directly_linked_links().is_empty()) {
1168 bNodeLink *displaced_link = linked_socket->directly_linked_links().first();
1170 if (!replacement_socket) {
1175 displaced_link->
tosock = replacement_socket;
1177 if (replacement_socket->is_multi_input()) {
1179 for (
bNodeLink *existing_link : replacement_socket->
runtime->directly_linked_links) {
1194 if (link->fromsock == linked_socket) {
1195 if (replacement_socket) {
1196 link->fromsock = replacement_socket;
1227 if (linked_socket.is_input()) {
1229 if (link->tosock != &linked_socket) {
1232 if (link->fromnode == start_node) {
1238 link->tosock = start_socket;
1239 link->tonode = start_node;
1244 if (link->fromsock != &linked_socket) {
1247 if (link->tonode == start_node) {
1252 link->fromsock = start_socket;
1253 link->fromnode = start_node;
1268 ntree.ensure_topology_cache();
1272 if (linked_socket.is_input()) {
1275 if (duplicate_link) {
1276 links_to_remove.
add(link);
1283 const bool duplicate_link = link->
tosock == dragged_link.
tosock;
1284 if (duplicate_link) {
1285 links_to_remove.
add(link);
1293 const bool link_limit_exceeded = !(link_count < link_limit);
1294 if (link_limit_exceeded) {
1295 if (links_to_remove.
add(link)) {
1301 for (
bNodeLink *link : links_to_remove) {
1316 const bool connecting_to_multi_input = linked_socket->is_multi_input() ||
1318 if (nldrag.
swap_links && !connecting_to_multi_input) {
1393 bNode &tnode = tsock->owner_node();
1401 bNodeLink *existing_link_connected_to_fromsock =
nullptr;
1403 if (existing_link->fromsock == link.
fromsock && existing_link->tosock == tsock) {
1404 existing_link_connected_to_fromsock = existing_link;
1413 if (existing_link_connected_to_fromsock) {
1417 if (tsock && tsock->is_multi_input()) {
1437 bNode &node = tsock->owner_node();
1444 if (link.
tonode == &node) {
1477 {0,
nullptr, 0,
nullptr,
nullptr},
1504 nldrag.
cursor[0] =
event->mval[0];
1505 nldrag.
cursor[1] =
event->mval[1];
1508 switch (event->
val) {
1562 tree.ensure_topology_cache();
1565 if (!link->is_available()) {
1578 snode.
edittree->ensure_topology_cache();
1579 bNode &node = sock->owner_node();
1581 std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
1582 nldrag->start_node = &node;
1583 nldrag->start_socket = sock;
1586 if (nldrag->start_link_count > 0 && (nldrag->start_link_count >= link_limit || detach)) {
1591 if (link->fromsock == sock) {
1593 oplink.
next = oplink.
prev =
nullptr;
1596 nldrag->links.append(oplink);
1611 snode.
edittree->ensure_topology_cache();
1612 bNode &node = sock->owner_node();
1613 std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
1614 nldrag->last_node_hovered_while_dragging_a_link = &node;
1615 nldrag->start_node = &node;
1616 nldrag->start_socket = sock;
1619 if (nldrag->start_link_count > 0) {
1625 if (link->tosock == sock) {
1626 link_to_pick = link;
1630 if (link_to_pick !=
nullptr && !nldrag->start_socket->is_multi_input()) {
1632 oplink.
next = oplink.
prev =
nullptr;
1635 nldrag->links.append(oplink);
1670 std::unique_ptr<bNodeLinkDrag> nldrag =
node_link_init(region, snode, cursor, detach);
1692 ot->name =
"Link Nodes";
1693 ot->idname =
"NODE_OT_link";
1694 ot->description =
"Use the mouse to create a link between two nodes";
1705 RNA_def_boolean(
ot->srna,
"detach",
false,
"Detach",
"Detach and redirect existing links");
1713 "The position of the mouse cursor at the start of the operation",
1756 ot->name =
"Make Links";
1757 ot->description =
"Make a link between selected output and input sockets";
1758 ot->idname =
"NODE_OT_link_make";
1769 ot->srna,
"replace",
false,
"Replace",
"Replace socket connections with the new links");
1791 if (path.
size() >= 256) {
1806 node_tree.ensure_topology_cache();
1821 links_to_remove.
add(link);
1826 for (
bNodeLink *link : links_to_remove) {
1827 bNode *to_node = link->tonode;
1829 affected_nodes.
add(to_node);
1832 node_tree.ensure_topology_cache();
1833 for (
bNode *node : affected_nodes) {
1847 ot->name =
"Cut Links";
1848 ot->idname =
"NODE_OT_links_cut";
1849 ot->description =
"Use the mouse to cut (remove) some links";
1878 for (
const bNodeLink *link : socket.directly_linked_links()) {
1900 if (path.
size() >= 256) {
1912 ntree.ensure_topology_cache();
1922 affected_links.
add(link);
1931 for (
bNodeLink *link : affected_links) {
1936 if (link->tonode->is_reroute()) {
1938 links.
push_multiple(link->tonode->output_socket(0).directly_linked_links());
1942 if (!link->
tonode->is_reroute()) {
1949 if (link->fromnode->is_reroute()) {
1952 links.
push_multiple(link->fromnode->input_socket(0).directly_linked_links());
1956 if (!link->
fromnode->is_reroute()) {
1973 ot->name =
"Mute Links";
1974 ot->idname =
"NODE_OT_links_mute";
1975 ot->description =
"Use the mouse to mute links";
2009 for (
bNode *node : ntree.all_nodes()) {
2010 if (node->flag &
SELECT) {
2021 ot->name =
"Detach Links";
2022 ot->idname =
"NODE_OT_links_detach";
2024 "Remove all links to selected nodes, and try to connect neighbor nodes together";
2044 if (!frame || !frame->is_frame()) {
2048 for (
bNode *node : ntree.all_nodes()) {
2049 if (node == frame) {
2067 ot->name =
"Make Parent";
2068 ot->description =
"Attach selected nodes";
2069 ot->idname =
"NODE_OT_parent_set";
2096 join_states[node->index()].done =
true;
2098 if (node == frame) {
2099 join_states[node->index()].descendent =
true;
2103 if (!join_states[node->
parent->index()].done) {
2108 if (join_states[node->
parent->index()].descendent) {
2109 join_states[node->index()].descendent =
true;
2111 else if (selected_nodes.
contains(node)) {
2115 join_states[node->index()].descendent =
true;
2118 else if (selected_nodes.
contains(node)) {
2120 join_states[node->index()].descendent =
true;
2131 std::reverse(parents.
begin(), parents.
end());
2137 if (
nodes.is_empty()) {
2142 for (
const bNode *node :
nodes.drop_front(1)) {
2148 if (candidates[
i] != parents[
i]) {
2160 return candidates.
last();
2175 ntree.ensure_topology_cache();
2179 for (
bNode *node : ntree.all_nodes()) {
2180 if (!join_states[node->index()].done) {
2215 ot->name =
"Join Nodes in Frame";
2216 ot->description =
"Attach selected nodes to a new common frame";
2217 ot->idname =
"NODE_OT_join";
2236 bNode *main_node =
nullptr;
2237 if (group_inputs.
contains(active_node)) {
2238 main_node = active_node;
2241 main_node = group_inputs[0];
2244 for (
const bNode *node : group_inputs) {
2245 location += node->location;
2247 location /=
float(group_inputs.size());
2250 tree.ensure_topology_cache();
2252 for (
bNode *node : group_inputs) {
2253 for (
bNodeSocket *socket : node->output_sockets().drop_back(1)) {
2254 old_link_map.
add_multiple(socket, socket->directly_linked_links());
2258 for (
bNodeSocket *socket : main_node->output_sockets()) {
2259 used_link_targets.
add_multiple(socket, socket->directly_linked_sockets());
2261 for (
bNode *node : group_inputs) {
2262 if (node == main_node) {
2265 bool keep_node =
false;
2268 for (
const int group_input_i : node->runtime->outputs.index_range().drop_back(1)) {
2269 bool keep_socket =
false;
2274 if (used_link_targets.
lookup(&new_socket).contains(&to_socket)) {
2279 used_link_targets.
add(&new_socket, &to_socket);
2280 link->fromsock = &new_socket;
2281 link->fromnode = main_node;
2303 if (selected_nodes.
size() <= 1) {
2307 if (std::all_of(selected_nodes.
begin(), selected_nodes.
end(), [](
const bNode *node) {
2308 return node->is_group_input();
2326 ot->name =
"Join Nodes";
2327 ot->description =
"Merge selected group input nodes into one if possible";
2328 ot->idname =
"NODE_OT_join_nodes";
2350 if (!frame->is_frame() || (frame->flag &
NODE_SELECT)) {
2367 if (node.
parent ==
nullptr) {
2370 if (node.
parent == &frame) {
2375 if (!share_parent) {
2387 if (frame ==
nullptr) {
2392 bool changed =
false;
2416 ot->name =
"Attach Nodes";
2417 ot->description =
"Attach active node to a frame";
2418 ot->idname =
"NODE_OT_attach";
2441 detach_states[node->index()].done =
true;
2445 if (!detach_states[node->
parent->index()].done) {
2450 if (detach_states[node->
parent->index()].descendent) {
2451 detach_states[node->index()].descendent =
true;
2456 detach_states[node->index()].descendent =
true;
2460 detach_states[node->index()].descendent =
true;
2473 for (
bNode *node : ntree.all_nodes()) {
2474 if (!detach_states[node->index()].done) {
2488 ot->name =
"Detach Nodes";
2489 ot->description =
"Detach selected nodes from parents";
2490 ot->idname =
"NODE_OT_detach";
2508 bNode *selected_node =
nullptr;
2509 int selected_node_count = 0;
2510 for (
bNode *node : node_tree.all_nodes()) {
2511 if (node->flag &
SELECT) {
2512 selected_node = node;
2513 selected_node_count++;
2515 if (selected_node_count > 1) {
2519 if (!selected_node) {
2522 if (selected_node->input_sockets().is_empty() || selected_node->output_sockets().is_empty()) {
2525 return selected_node;
2532 if (
ELEM(
nullptr, main_input, main_output)) {
2535 if (node.is_reroute()) {
2538 if (!
tree.typeinfo->validate_link) {
2556 const bool attach_enabled,
2557 const bool is_new_node)
2560 node_tree.ensure_topology_cache();
2565 if (!node_to_insert) {
2569 for (
bNodeSocket *socket : node_to_insert->input_sockets()) {
2570 already_linked_sockets.
extend(socket->directly_linked_sockets());
2572 for (
bNodeSocket *socket : node_to_insert->output_sockets()) {
2573 already_linked_sockets.
extend(socket->directly_linked_sockets());
2575 if (!is_new_node && !already_linked_sockets.
is_empty()) {
2586 if (
ELEM(node_to_insert, link->fromnode, link->tonode)) {
2590 if (is_new_node && !already_linked_sockets.
is_empty()) {
2593 bool is_linked_to_linked =
false;
2594 for (
const bNodeSocket *socket : already_linked_sockets) {
2595 if (
ELEM(socket, link->fromsock, link->tosock)) {
2596 is_linked_to_linked =
true;
2600 if (!is_linked_to_linked) {
2605 std::array<float2, NODE_LINK_RESOL + 1> coords;
2616 const float node_xy[] = {node_to_insert->
runtime->draw_bounds.xmin,
2617 node_to_insert->
runtime->draw_bounds.ymax};
2626 if (dist < dist_best) {
2646 snode.
edittree->ensure_topology_cache();
2679 node_tree.ensure_topology_cache();
2681 if (!node_to_insert) {
2697 if (old_link ==
nullptr) {
2703 for (
bNodeSocket *socket : node_to_insert->input_sockets()) {
2704 if (!socket->directly_linked_sockets().is_empty()) {
2705 best_input = socket;
2715 for (
bNodeSocket *socket : node_to_insert->output_sockets()) {
2716 if (!socket->directly_linked_sockets().is_empty()) {
2717 best_output = socket;
2726 if (!node_to_insert->is_reroute()) {
2728 if (best_input !=
nullptr && ntree.
typeinfo->validate_link !=
nullptr &&
2732 best_input =
nullptr;
2734 if (best_output !=
nullptr && ntree.
typeinfo->validate_link !=
nullptr &&
2738 best_output =
nullptr;
2746 const bool best_input_is_linked = best_input && best_input->is_directly_linked();
2748 if (best_output !=
nullptr) {
2750 old_link->
fromnode = node_to_insert;
2758 if (best_input !=
nullptr) {
2760 if (!best_input_is_linked) {
2771 iofsd->
insert = node_to_insert;
2772 iofsd->
prev = from_node;
2773 iofsd->
next = to_node;
2828 if (node_decl !=
nullptr) {
2832 if (!socket_decl->is_default_link_socket) {
2836 if (socket && socket->is_visible()) {
2843 int maxpriority = -1;
2852 for (
int priority = maxpriority; priority >= 0; priority--) {
2880#define NODE_INSOFS_ANIM_DURATION 0.25f
2889 const bool reversed)
2892 bNode *ofs_node = reversed ? fromnode : tonode;
2901 const int mouse_xy[2],
2902 const bool right_alignment)
2911 const bool needs_alignment = (
next->runtime->draw_bounds.xmin -
2912 prev->runtime->draw_bounds.xmax) < (width + (min_margin * 2.0f));
2914 float margin = width;
2932 (prev->parent && (prev->parent ==
next->parent) && (prev->parent !=
insert.parent)))
2939 if (!frame->is_frame() || (frame->flag &
NODE_SELECT)) {
2963 float dist = right_alignment ? totr_insert.
xmin - prev->runtime->draw_bounds.xmax :
2964 next->runtime->draw_bounds.xmin - totr_insert.
xmax;
2966 if (dist < min_margin) {
2967 const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
2971 totr_insert.
xmin += addval;
2972 totr_insert.
xmax += addval;
2973 margin += min_margin;
2978 dist = right_alignment ?
next->runtime->draw_bounds.xmin - totr_insert.
xmax :
2979 totr_insert.
xmin - prev->runtime->draw_bounds.xmax;
2981 if (dist < min_margin) {
2982 const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
2983 if (needs_alignment) {
2984 bNode *offs_node = right_alignment ?
next : prev;
2995 if (needs_alignment) {
3002 right_alignment ?
next : prev,
3008 insert.parent = init_parent;
3018 bool redraw =
false;
3030 if (
UNLIKELY(node->runtime->anim_ofsx)) {
3034 if (prev_duration < clamped_duration) {
3035 const float offset_step = node->runtime->anim_ofsx *
3040 node->location[0] += offset_step;
3054 node->runtime->anim_ofsx = 0.0f;
3065#undef NODE_INSOFS_ANIM_DURATION
3076 if (!iofsd || !iofsd->
insert) {
3097 ot->name =
"Insert Offset";
3098 ot->description =
"Automatically offset nodes on insertion";
3099 ot->idname =
"NODE_OT_insert_offset";
SpaceNode * CTX_wm_space_node(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
void BKE_ntree_update_tag_active_output_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *link)
void BKE_report(ReportList *reports, eReportType type, const char *message)
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
void BLI_kdtree_nd_ insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
bool BLI_rctf_isect_x(const rctf *rect, float x)
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest)
bool BLI_rctf_isect_y(const rctf *rect, float y)
bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2])
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
@ NODE_VIEWER_SHORTCUT_NONE
@ NODE_LINK_TEMP_HIGHLIGHT
@ NODE_LINK_INSERT_TARGET
@ NODE_LINK_INSERT_TARGET_INVALID
@ NODE_GEO_VIEWER_ITEM_FLAG_AUTO_REMOVE
@ SNODE_INSERTOFS_DIR_RIGHT
bool ED_node_is_geometry(const SpaceNode *snode)
bool ED_node_is_compositor(const SpaceNode *snode)
#define NODE_EDGE_PAN_OUTSIDE_PAD
#define NODE_EDGE_PAN_INSIDE_PAD
#define NODE_EDGE_PAN_MAX_SPEED
#define NODE_EDGE_PAN_DELAY
#define NODE_EDGE_PAN_ZOOM_INFLUENCE
#define NODE_EDGE_PAN_SPEED_RAMP
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
void ED_area_tag_redraw(ScrArea *area)
bool ED_operator_node_editable(bContext *C)
void ED_workspace_status_text(bContext *C, const char *str)
void ED_region_tag_redraw(ARegion *region)
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
#define REGION_DRAW_POST_PIXEL
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Read Guarded memory(de)allocation.
#define RNA_BEGIN(sptr, itemptr, propname)
#define UI_PRECISION_FLOAT_MAX
#define UI_NO_ICON_OVERLAY_TEXT
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border, const IconTextOverlay *text_overlay, const bool inverted=false)
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
void UI_view2d_edge_pan_operator_init(bContext *C, View2DEdgePanData *vpd, wmOperator *op)
void UI_view2d_edge_pan_cancel(bContext *C, View2DEdgePanData *vpd)
void UI_view2d_edge_pan_operator_properties_ex(wmOperatorType *ot, float inside_pad, float outside_pad, float speed_ramp, float max_speed, float delay, float zoom_influence)
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
void void UI_view2d_edge_pan_apply_event(bContext *C, View2DEdgePanData *vpd, const wmEvent *event)
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
@ OPTYPE_DEPENDS_ON_CURSOR
ccl_device_inline float arc_length(const float e2, const float gamma)
void append(const T &value)
Span< Value > lookup(const Key &key) const
void add_multiple(const Key &key, Span< Value > values)
void add(const Key &key, const Value &value)
constexpr bool contains(const T &value) const
void push_multiple(Span< T > values)
const Key * begin() const
bool contains(const Key &key) const
Span< Key > as_span() const
void append(const T &value)
const T & last(const int64_t n=0) const
IndexRange index_range() const
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void extend(Span< T > array)
Vector< SocketDeclaration * > inputs
Vector< SocketDeclaration * > outputs
float distance(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_mallocN(size_t len, const char *str)
void * MEM_callocN(size_t len, const char *str)
void MEM_freeN(void *vmemh)
bool node_is_parent_and_child(const bNode &parent, const bNode &child)
void node_attach_node(bNodeTree &ntree, bNode &node, bNode &parent)
bNode * node_get_active(bNodeTree &ntree)
void node_remove_link(bNodeTree *ntree, bNodeLink &link)
void node_chain_iterator(const bNodeTree *ntree, const bNode *node_start, bool(*callback)(bNode *, bNode *, void *, const bool), void *userdata, bool reversed)
void node_parents_iterator(bNode *node, bool(*callback)(bNode *, void *), void *userdata)
int node_count_socket_links(const bNodeTree &ntree, const bNodeSocket &sock)
void node_internal_relink(bNodeTree &ntree, bNode &node)
void node_free_node(bNodeTree *tree, bNode &node)
void node_detach_node(bNodeTree &ntree, bNode &node)
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
void node_link_set_mute(bNodeTree &ntree, bNodeLink &link, const bool muted)
void node_remove_socket_links(bNodeTree &ntree, bNodeSocket &sock)
bool node_declaration_ensure(bNodeTree &ntree, bNode &node)
void node_set_active(bNodeTree &ntree, bNode &node)
int node_socket_link_limit(const bNodeSocket &sock)
void node_tree_node_flag_set(bNodeTree &ntree, int flag, bool enable)
void move_index(T *items, const int items_num, const int from_index, const int to_index)
static int view_socket(const bContext &C, SpaceNode &snode, bNodeTree &btree, bNode &bnode_to_view, bNodeSocket &bsocket_to_view)
static const bNode * find_overlapping_node(const bNodeTree &tree, const rctf &rect, const Span< const bNode * > ignored_nodes)
static int node_link_viewer(const bContext &C, bNode &bnode_to_view, bNodeSocket *bsocket_to_view)
static bNodeSocket * determine_socket_to_view(bNode &node_to_view)
static void finalize_viewer_link(const bContext &C, SpaceNode &snode, bNode &viewer_node, bNodeLink &viewer_link)
static std::string get_viewer_source_name(const bNodeSocket &socket)
static bNodeSocket * node_link_viewer_get_socket(bNodeTree &ntree, bNode &viewer_node, bNodeSocket &src_socket)
static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &viewer_node)
static bool is_viewer_socket(const bNodeSocket &socket)
static bool is_viewer_node(const bNode &node)
static bool socket_can_be_viewed(const bNodeSocket &socket)
static bool is_viewer_socket_in_viewer(const bNodeSocket &socket)
static int ensure_geometry_nodes_viewer_has_non_geometry_socket(bNodeTree &ntree, bNode &viewer_node, const eNodeSocketDatatype socket_type)
static Vector< float2 > get_viewer_node_position_candidates(const float2 initial, const float step_distance, const float max_distance)
static int get_default_viewer_type(const bContext *C)
static void position_viewer_node(const bContext &C, bNodeTree &tree, bNode &viewer_node, const bNode &node_to_view)
static void ensure_geometry_nodes_viewer_starts_with_geometry_socket(bNodeTree &tree, bNode &viewer_node)
void NODE_OT_parent_set(wmOperatorType *ot)
static void join_group_inputs(bNodeTree &tree, VectorSet< bNode * > group_inputs, bNode *active_node)
static wmOperatorStatus node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void draw_draglink_tooltip_activate(const ARegion ®ion, bNodeLinkDrag &nldrag)
void node_deselect_all_input_sockets(bNodeTree &node_tree, bool deselect_nodes)
NodeLinkData data[NODELINK_GROUP_SIZE]
void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion ®ion, bool attach_enabled, bool is_new_node)
static wmOperatorStatus mute_links_exec(bContext *C, wmOperator *op)
static void node_swap_links(bNodeLinkDrag &nldrag, bNodeTree &ntree)
void tree_draw_order_update(bNodeTree &ntree)
static bool need_drag_link_tooltip(const bNodeTree &node_tree, const bNodeLinkDrag &nldrag)
static wmOperatorStatus node_join_in_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bNodeLink create_drag_link(bNode &node, bNodeSocket &socket)
static void clear_picking_highlight(ListBase *links)
static void sort_multi_input_socket_links_with_drag(bNodeSocket &socket, bNodeLink &drag_link, const float2 &cursor)
bNode * add_static_node(const bContext &C, int type, const float2 &location)
static std::unique_ptr< bNodeLinkDrag > node_link_init(ARegion ®ion, SpaceNode &snode, const float2 cursor, const bool detach)
void invoke_node_link_drag_add_menu(bContext &C, bNode &node, bNodeSocket &socket, const float2 &cursor)
static wmOperatorStatus node_active_link_viewer_exec(bContext *C, wmOperator *)
void NODE_OT_detach(wmOperatorType *ot)
static Vector< const bNode * > get_sorted_node_parents(const bNode &node)
bool all_links_muted(const bNodeSocket &socket)
static bool can_attach_node_to_frame(const bNode &node, const bNode &frame)
bNodeSocket * node_find_indicated_socket(SpaceNode &snode, ARegion ®ion, const float2 &cursor, const eNodeSocketInOut in_out)
static bNodeSocket * node_find_linkable_socket(const bNodeTree &ntree, const bNode *node, bNodeSocket *socket_to_match)
static wmOperatorStatus node_insert_offset_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
void NODE_OT_insert_offset(wmOperatorType *ot)
Array< bNode * > tree_draw_order_calc_nodes_reversed(bNodeTree &ntree)
static int get_main_socket_priority(const bNodeSocket *socket)
static bool snode_autoconnect_input(bContext &C, SpaceNode &snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
static Vector< bNodeSocket * > get_available_sorted_inputs(const bNodeTree *ntree, const bNode *node, const bool only_unlinked)
float2 node_link_calculate_multi_input_position(const float2 &socket_position, const int index, const int total_inputs)
void NODE_OT_links_detach(wmOperatorType *ot)
static bool dragged_links_are_detached(const bNodeLinkDrag &nldrag)
void NODE_OT_links_cut(wmOperatorType *ot)
static void pick_input_link_by_link_intersect(const bContext &C, wmOperator &op, bNodeLinkDrag &nldrag, const float2 &cursor)
static wmOperatorStatus node_attach_invoke(bContext *C, wmOperator *, const wmEvent *event)
static void node_detach_recursive(bNodeTree &ntree, MutableSpan< NodeDetachstate > detach_states, bNode *node)
static void node_displace_existing_links(bNodeLinkDrag &nldrag, bNodeTree &ntree)
static void node_link_cancel(bContext *C, wmOperator *op)
static void pick_link(bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick)
static void displace_links(bNodeTree *ntree, const bNode *node, bNodeLink *inserted_link)
static wmOperatorStatus node_join_nodes_exec(bContext *C, wmOperator *op)
static wmOperatorStatus node_join_in_frame_exec(bContext *C, wmOperator *)
void NODE_OT_join(wmOperatorType *ot)
static void snode_autoconnect(bContext &C, SpaceNode &snode, const bool allow_multiple, const bool replace)
static bNode * node_find_frame_to_attach(ARegion ®ion, bNodeTree &ntree, const int2 mouse_xy)
static bool node_active_link_viewer_poll(bContext *C)
static wmOperatorStatus node_detach_exec(bContext *C, wmOperator *)
static bool socket_is_available(const bNodeTree *ntree, bNodeSocket *sock, const bool allow_used)
static wmOperatorStatus detach_links_exec(bContext *C, wmOperator *)
static bool node_can_be_inserted_on_link(bNodeTree &tree, bNode &node, const bNodeLink &link)
void NODE_OT_attach(wmOperatorType *ot)
void node_insert_on_frame_flag_set(bContext &C, SpaceNode &snode, const int2 &cursor)
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
static void draw_draglink_tooltip_deactivate(const ARegion ®ion, bNodeLinkDrag &nldrag)
std::optional< float2 > link_path_intersection(const bNodeLink &link, const Span< float2 > path)
void NODE_OT_link_viewer(wmOperatorType *ot)
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
void node_deselect_all_output_sockets(bNodeTree &node_tree, bool deselect_nodes)
static wmOperatorStatus node_insert_offset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float2 node_to_view(const float2 &co)
void node_insert_on_link_flags_clear(bNodeTree &node_tree)
static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag)
static void remove_unavailable_links(bNodeTree &tree, bNodeSocket &socket)
static wmOperatorStatus node_parent_set_exec(bContext *C, wmOperator *)
void NODE_OT_link_make(wmOperatorType *ot)
void node_link_bezier_points_evaluated(const bNodeLink &link, std::array< float2, NODE_LINK_RESOL+1 > &coords)
wmKeyMap * node_link_modal_keymap(wmKeyConfig *keyconf)
static wmOperatorStatus node_make_link_exec(bContext *C, wmOperator *op)
void NODE_OT_join_nodes(wmOperatorType *ot)
static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, ARegion *region, const int mouse_xy[2], const bool right_alignment)
static bNodeSocket * best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, const bool allow_multiple)
static int node_socket_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
static bool node_link_insert_offset_chain_cb(bNode *fromnode, bNode *tonode, void *userdata, const bool reversed)
void node_to_updated_rect(const bNode &node, rctf &r_rect)
static bool should_create_drag_link_search_menu(const bNodeTree &node_tree, const bNodeLinkDrag &nldrag)
static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cursor)
void NODE_OT_link(wmOperatorType *ot)
void NODE_OT_links_mute(wmOperatorType *ot)
void node_insert_on_frame_flag_clear(SpaceNode &snode)
static const bNode * find_common_parent_node(const Span< const bNode * > nodes)
bNodeSocket * get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
static void node_join_attach_recursive(bNodeTree &ntree, MutableSpan< NodeJoinState > join_states, bNode *node, bNode *frame, const VectorSet< bNode * > &selected_nodes)
void update_multi_input_indices_for_removed_links(bNode &node)
void node_insert_on_link_flags(Main &bmain, SpaceNode &snode, bool is_new_node)
static bool node_parents_offset_flag_enable_cb(bNode *parent, void *)
static void node_remove_existing_links_if_needed(bNodeLinkDrag &nldrag, bNodeTree &ntree)
static wmOperatorStatus cut_links_exec(bContext *C, wmOperator *op)
static void node_offset_apply(bNode &node, const float offset_x)
static bNode * get_selected_node_for_insertion(bNodeTree &node_tree)
static void draw_draglink_tooltip(const bContext *, ARegion *, void *arg)
void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node, std::optional< int > item_identifier=std::nullopt)
T min(const T &a, const T &b)
void set_item_name_and_make_unique(bNode &node, typename Accessor::ItemT &item, const char *value)
Accessor::ItemT * find_item_by_identifier(bNode &node, const StringRef identifier)
Accessor::ItemT * add_item_with_socket_type_and_name(bNodeTree &ntree, bNode &node, const eNodeSocketDatatype socket_type, const char *name, std::optional< int > dimensions=std::nullopt)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
#define NODE_INSOFS_ANIM_DURATION
static blender::bke::bNodeSocketTemplate inputs[]
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_array(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
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)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
ARegionRuntimeHandle * runtime
NodeGeometryViewerItem * items
SpaceNode_Runtime * runtime
struct bNodeTree * edittree
struct bNodeTree * nodetree
bNodeSocketRuntimeHandle * runtime
bNodeSocketTypeHandle * typeinfo
struct bNodeSocket * next
bNodeTreeTypeHandle * typeinfo
bNodeTypeHandle * typeinfo
bNodeRuntimeHandle * runtime
float2 multi_socket_position
std::optional< int > frame_identifier_to_highlight
std::unique_ptr< bNodeLinkDrag > linkdrag
NodeInsertOfsData * iofsd
Vector< bNodeLink > links
View2DEdgePanData pan_data
bNodeSocket * hovered_socket
bNodeLink * last_picked_multi_input_socket_link
bNode * last_node_hovered_while_dragging_a_link
std::array< int, 2 > cursor
bNodeSocket * start_socket
static bool supports_socket_type(const eNodeSocketDatatype socket_type, const int)
struct ReportList * reports
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_lines_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)