Blender V4.3
node_select.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <array>
10#include <cstdlib>
11#include <iostream>
12
13#include "DNA_node_types.h"
15
16#include "BLI_lasso_2d.hh"
17#include "BLI_listbase.h"
18#include "BLI_rect.h"
19#include "BLI_string.h"
20#include "BLI_string_utf8.h"
21#include "BLI_utildefines.h"
22
23#include "BKE_context.hh"
24#include "BKE_main.hh"
25#include "BKE_node.hh"
26#include "BKE_node_runtime.hh"
28#include "BKE_workspace.hh"
29
30#include "ED_node.hh" /* own include */
31#include "ED_screen.hh"
32#include "ED_select_utils.hh"
33#include "ED_view3d.hh"
34#include "ED_viewer_path.hh"
35
36#include "RNA_access.hh"
37#include "RNA_define.hh"
38
39#include "WM_api.hh"
40#include "WM_types.hh"
41
42#include "UI_interface.hh"
43#include "UI_resources.hh"
44#include "UI_string_search.hh"
45#include "UI_view2d.hh"
46
47#include "DEG_depsgraph.hh"
48
49#include "MEM_guardedalloc.h"
50
51#include "node_intern.hh" /* own include */
52
54
55static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event);
56
67 const Scene *scene,
68 const Object *ob)
69{
70 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
71 if (win->scene != scene) {
72 continue;
73 }
74 const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
75 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
76 if (area->spacetype == SPACE_VIEW3D) {
77 const View3D *v3d = (const View3D *)area->spacedata.first;
78
79 if (ED_view3d_has_workbench_in_texture_color(scene, ob, v3d)) {
80 return true;
81 }
82 }
83 }
84 }
85 return false;
86}
87
88/* -------------------------------------------------------------------- */
92rctf node_frame_rect_inside(const SpaceNode &snode, const bNode &node)
93{
94 const float margin = 4.0f * NODE_RESIZE_MARGIN * math::max(snode.runtime->aspect, 1.0f);
95 rctf frame_inside = {
96 node.runtime->totr.xmin,
97 node.runtime->totr.xmax,
98 node.runtime->totr.ymin,
99 node.runtime->totr.ymax,
100 };
101
102 BLI_rctf_pad(&frame_inside, -margin, -margin);
103
104 return frame_inside;
105}
106
107bool node_or_socket_isect_event(const bContext &C, const wmEvent &event)
108{
109 return is_event_over_node_or_socket(C, event);
110}
111
113 const bNode &node,
114 const float2 &mouse)
115{
116 /* Frame nodes are selectable by their borders (including their whole rect - as for other nodes -
117 * would prevent e.g. box selection of nodes inside that frame). */
118 const rctf frame_inside = node_frame_rect_inside(snode, node);
119 if (BLI_rctf_isect_pt(&node.runtime->totr, mouse.x, mouse.y) &&
120 !BLI_rctf_isect_pt(&frame_inside, mouse.x, mouse.y))
121 {
122 return true;
123 }
124
125 return false;
126}
127
128static bNode *node_under_mouse_select(const SpaceNode &snode, const float2 mouse)
129{
131 switch (node->type) {
132 case NODE_FRAME: {
133 if (node_frame_select_isect_mouse(snode, *node, mouse)) {
134 return node;
135 }
136 break;
137 }
138 default: {
139 if (BLI_rctf_isect_pt(&node->runtime->totr, int(mouse.x), int(mouse.y))) {
140 return node;
141 }
142 break;
143 }
144 }
145 }
146 return nullptr;
147}
148
149static bool node_under_mouse_tweak(const SpaceNode &snode, const float2 &mouse)
150{
152 switch (node->type) {
153 case NODE_REROUTE: {
154 const float2 location = node_to_view(*node, {node->locx, node->locy});
155 if (math::distance_squared(mouse, location) < square_f(24.0f)) {
156 return true;
157 }
158 break;
159 }
160 case NODE_FRAME: {
161 if (node_frame_select_isect_mouse(snode, *node, mouse)) {
162 return true;
163 }
164 break;
165 }
166 default: {
167 if (BLI_rctf_isect_pt(&node->runtime->totr, mouse.x, mouse.y)) {
168 return true;
169 }
170 break;
171 }
172 }
173 }
174 return false;
175}
176
177static bool is_position_over_node_or_socket(SpaceNode &snode, ARegion &region, const float2 &mouse)
178{
179 if (node_under_mouse_tweak(snode, mouse)) {
180 return true;
181 }
182 if (node_find_indicated_socket(snode, region, mouse, SOCK_IN | SOCK_OUT)) {
183 return true;
184 }
185 return false;
186}
187
188static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event)
189{
190 SpaceNode &snode = *CTX_wm_space_node(&C);
191 ARegion &region = *CTX_wm_region(&C);
192
193 int2 mval;
194 WM_event_drag_start_mval(&event, &region, mval);
195
196 float2 mouse;
197 UI_view2d_region_to_view(&region.v2d, mval.x, mval.y, &mouse.x, &mouse.y);
198 return is_position_over_node_or_socket(snode, region, mouse);
199}
200
202{
203 sock.flag |= SELECT;
204
205 /* select node too */
206 if (node) {
207 node->flag |= SELECT;
208 }
209}
210
211void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node)
212{
213 sock.flag &= ~SELECT;
214
215 if (node && deselect_node) {
216 bool sel = false;
217
218 /* if no selected sockets remain, also deselect the node */
219 LISTBASE_FOREACH (bNodeSocket *, input, &node->inputs) {
220 if (input->flag & SELECT) {
221 sel = true;
222 break;
223 }
224 }
225 LISTBASE_FOREACH (bNodeSocket *, output, &node->outputs) {
226 if (output->flag & SELECT) {
227 sel = true;
228 break;
229 }
230 }
231
232 if (!sel) {
233 node->flag &= ~SELECT;
234 }
235 }
236}
237
238static void node_socket_toggle(bNode *node, bNodeSocket &sock, bool deselect_node)
239{
240 if (sock.flag & SELECT) {
241 node_socket_deselect(node, sock, deselect_node);
242 }
243 else {
244 node_socket_select(node, sock);
245 }
246}
247
249{
250 bool changed = false;
251 for (bNode *node : node_tree.all_nodes()) {
252 changed |= bke::node_set_selected(node, false);
253 }
254 return changed;
255}
256
257void node_deselect_all_input_sockets(bNodeTree &node_tree, const bool deselect_nodes)
258{
259 /* XXX not calling node_socket_deselect here each time, because this does iteration
260 * over all node sockets internally to check if the node stays selected.
261 * We can do that more efficiently here.
262 */
263
264 for (bNode *node : node_tree.all_nodes()) {
265 bool sel = false;
266
267 LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
268 socket->flag &= ~SELECT;
269 }
270
271 /* If no selected sockets remain, also deselect the node. */
272 if (deselect_nodes) {
273 LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
274 if (socket->flag & SELECT) {
275 sel = true;
276 break;
277 }
278 }
279
280 if (!sel) {
281 node->flag &= ~SELECT;
282 }
283 }
284 }
285}
286
287void node_deselect_all_output_sockets(bNodeTree &node_tree, const bool deselect_nodes)
288{
289 /* XXX not calling node_socket_deselect here each time, because this does iteration
290 * over all node sockets internally to check if the node stays selected.
291 * We can do that more efficiently here.
292 */
293
294 for (bNode *node : node_tree.all_nodes()) {
295 bool sel = false;
296
297 LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
298 socket->flag &= ~SELECT;
299 }
300
301 /* if no selected sockets remain, also deselect the node */
302 if (deselect_nodes) {
303 LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
304 if (socket->flag & SELECT) {
305 sel = true;
306 break;
307 }
308 }
309
310 if (!sel) {
311 node->flag &= ~SELECT;
312 }
313 }
314 }
315}
316
318{
319 node_tree.ensure_topology_cache();
320 for (const bke::bNodeZoneType *zone_type : bke::all_zone_types()) {
321 for (bNode *input_node : node_tree.nodes_by_type(zone_type->input_idname)) {
322 if (bNode *output_node = zone_type->get_corresponding_output(node_tree, *input_node)) {
323 if (input_node->flag & NODE_SELECT) {
324 output_node->flag |= NODE_SELECT;
325 }
326 if (output_node->flag & NODE_SELECT) {
327 input_node->flag |= NODE_SELECT;
328 }
329 }
330 }
331 }
332}
333
335{
336 VectorSet<bNode *> selected_nodes;
337 for (bNode *node : node_tree.all_nodes()) {
338 if (node->flag & NODE_SELECT) {
339 selected_nodes.add(node);
340 }
341 }
342 return selected_nodes;
343}
344
347/* -------------------------------------------------------------------- */
351/* Return true if we need redraw, otherwise false. */
352
354{
355 bool changed = false;
356 for (bNode *node : node_tree.all_nodes()) {
357 if ((node->flag & SELECT) == 0) {
358 if (node->type == node_act.type) {
359 bke::node_set_selected(node, true);
360 changed = true;
361 }
362 }
363 }
364 return changed;
365}
366
368{
369 bool changed = false;
370 for (bNode *node : node_tree.all_nodes()) {
371 if ((node->flag & SELECT) == 0) {
372 if (compare_v3v3(node->color, node_act.color, 0.005f)) {
373 bke::node_set_selected(node, true);
374 changed = true;
375 }
376 }
377 }
378 return changed;
379}
380
381static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right)
382{
383 bool changed = false;
384 const uint delims[] = {'.', '-', '_', '\0'};
385 size_t pref_len_act, pref_len_curr;
386 const char *sep, *suf_act, *suf_curr;
387
388 pref_len_act = BLI_str_partition_ex_utf8(
389 node_act.name, nullptr, delims, &sep, &suf_act, from_right);
390
391 /* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */
392 if (from_right && !(sep && suf_act)) {
393 pref_len_act = 0;
394 suf_act = node_act.name;
395 }
396
397 for (bNode *node : node_tree.all_nodes()) {
398 if (node->flag & SELECT) {
399 continue;
400 }
401 pref_len_curr = BLI_str_partition_ex_utf8(
402 node->name, nullptr, delims, &sep, &suf_curr, from_right);
403
404 /* Same as with active node name! */
405 if (from_right && !(sep && suf_curr)) {
406 pref_len_curr = 0;
407 suf_curr = node->name;
408 }
409
410 if ((from_right && STREQ(suf_act, suf_curr)) ||
411 (!from_right && (pref_len_act == pref_len_curr) &&
412 STREQLEN(node_act.name, node->name, pref_len_act)))
413 {
414 bke::node_set_selected(node, true);
415 changed = true;
416 }
417 }
418
419 return changed;
420}
421
422enum {
427};
428
430{
431 SpaceNode &snode = *CTX_wm_space_node(C);
432 bNodeTree &node_tree = *snode.edittree;
433 bNode *node_act = bke::node_get_active(snode.edittree);
434
435 if (node_act == nullptr) {
436 return OPERATOR_CANCELLED;
437 }
438
439 bool changed = false;
440 const bool extend = RNA_boolean_get(op->ptr, "extend");
441 const int type = RNA_enum_get(op->ptr, "type");
442
443 if (!extend) {
445 }
446 bke::node_set_selected(node_act, true);
447
448 switch (type) {
450 changed = node_select_grouped_type(node_tree, *node_act);
451 break;
453 changed = node_select_grouped_color(node_tree, *node_act);
454 break;
456 changed = node_select_grouped_name(node_tree, *node_act, false);
457 break;
459 changed = node_select_grouped_name(node_tree, *node_act, true);
460 break;
461 default:
462 break;
463 }
464
465 if (changed) {
468 return OPERATOR_FINISHED;
469 }
470
471 return OPERATOR_CANCELLED;
472}
473
475{
476 PropertyRNA *prop;
477 static const EnumPropertyItem prop_select_grouped_types[] = {
478 {NODE_SELECT_GROUPED_TYPE, "TYPE", 0, "Type", ""},
479 {NODE_SELECT_GROUPED_COLOR, "COLOR", 0, "Color", ""},
480 {NODE_SELECT_GROUPED_PREFIX, "PREFIX", 0, "Prefix", ""},
481 {NODE_SELECT_GROUPED_SUFIX, "SUFFIX", 0, "Suffix", ""},
482 {0, nullptr, 0, nullptr, nullptr},
483 };
484
485 /* identifiers */
486 ot->name = "Select Grouped";
487 ot->description = "Select nodes with similar properties";
488 ot->idname = "NODE_OT_select_grouped";
489
490 /* api callbacks */
494
495 /* flags */
497
498 /* properties */
499 prop = RNA_def_boolean(ot->srna,
500 "extend",
501 false,
502 "Extend",
503 "Extend selection instead of deselecting everything first");
505 ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
506}
507
510/* -------------------------------------------------------------------- */
515{
516 Main *bmain = CTX_data_main(&C);
517 SpaceNode &snode = *CTX_wm_space_node(&C);
518 bNodeTree &node_tree = *snode.edittree;
519 const Object *ob = CTX_data_active_object(&C);
520 const Scene *scene = CTX_data_scene(&C);
521 const wmWindowManager *wm = CTX_wm_manager(&C);
522 bool active_texture_changed = false;
523
524 for (bNode *node_iter : node_tree.all_nodes()) {
525 if (node_iter != &node) {
526 bke::node_set_selected(node_iter, false);
527 }
528 }
529 bke::node_set_selected(&node, true);
530
531 ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed);
533
535 if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
537 }
538
540}
541
543 wmOperator *op,
544 const int2 mval,
546{
547 Main &bmain = *CTX_data_main(C);
548 SpaceNode &snode = *CTX_wm_space_node(C);
549 bNodeTree &node_tree = *snode.edittree;
550 ARegion &region = *CTX_wm_region(C);
551 const Object *ob = CTX_data_active_object(C);
552 const Scene *scene = CTX_data_scene(C);
553 const wmWindowManager *wm = CTX_wm_manager(C);
554 bNode *node = nullptr;
555 bNodeSocket *sock = nullptr;
556
557 /* Always do socket_select when extending selection. */
558 const bool socket_select = (params->sel_op == SEL_OP_XOR) ||
559 RNA_boolean_get(op->ptr, "socket_select");
560 bool changed = false;
561 bool found = false;
562 bool node_was_selected = false;
563
564 /* Get mouse coordinates in view2d space. */
565 float2 cursor;
566 UI_view2d_region_to_view(&region.v2d, mval.x, mval.y, &cursor.x, &cursor.y);
567
568 /* First do socket selection, these generally overlap with nodes. */
569 if (socket_select) {
570 /* NOTE: unlike nodes #SelectPick_Params isn't fully supported. */
571 const bool extend = (params->sel_op == SEL_OP_XOR);
572 sock = node_find_indicated_socket(snode, region, cursor, SOCK_IN);
573 if (sock) {
574 node = &sock->owner_node();
575 found = true;
576 node_was_selected = node->flag & SELECT;
577
578 /* NOTE: SOCK_IN does not take into account the extend case...
579 * This feature is not really used anyway currently? */
580 node_socket_toggle(node, *sock, true);
581 changed = true;
582 }
583 if (!changed) {
584 sock = node_find_indicated_socket(snode, region, cursor, SOCK_OUT);
585 if (sock) {
586 node = &sock->owner_node();
587 found = true;
588 node_was_selected = node->flag & SELECT;
589
590 if (sock->flag & SELECT) {
591 if (extend) {
592 node_socket_deselect(node, *sock, true);
593 changed = true;
594 }
595 }
596 else {
597 /* Only allow one selected output per node, for sensible linking.
598 * Allow selecting outputs from different nodes though, if extend is true. */
599 for (bNodeSocket *tsock : node->output_sockets()) {
600 if (tsock == sock) {
601 continue;
602 }
603 node_socket_deselect(node, *tsock, true);
604 changed = true;
605 }
606 if (!extend) {
607 for (bNode *tnode : node_tree.all_nodes()) {
608 if (tnode == node) {
609 continue;
610 }
611 for (bNodeSocket *tsock : tnode->output_sockets()) {
612 node_socket_deselect(tnode, *tsock, true);
613 changed = true;
614 }
615 }
616 }
617 node_socket_select(node, *sock);
618 changed = true;
619 }
620 }
621 }
622 }
623
624 if (!sock) {
625
626 /* Find the closest visible node. */
627 node = node_under_mouse_select(snode, cursor);
628 found = (node != nullptr);
629 node_was_selected = node && (node->flag & SELECT);
630
631 if (params->sel_op == SEL_OP_SET) {
632 if ((found && params->select_passthrough) && (node->flag & SELECT)) {
633 found = false;
634 }
635 else if (found || params->deselect_all) {
636 /* Deselect everything. */
637 changed = node_deselect_all(node_tree);
638 }
639 }
640
641 if (found) {
642 switch (params->sel_op) {
643 case SEL_OP_ADD:
644 bke::node_set_selected(node, true);
645 break;
646 case SEL_OP_SUB:
647 bke::node_set_selected(node, false);
648 break;
649 case SEL_OP_XOR: {
650 /* Check active so clicking on an inactive node activates it. */
651 bool is_selected = (node->flag & NODE_SELECT) && (node->flag & NODE_ACTIVE);
652 bke::node_set_selected(node, !is_selected);
653 break;
654 }
655 case SEL_OP_SET:
656 bke::node_set_selected(node, true);
657 break;
658 case SEL_OP_AND:
659 /* Doesn't make sense for picking. */
661 break;
662 }
663
664 changed = true;
665 }
666 }
667
668 if (RNA_boolean_get(op->ptr, "clear_viewer")) {
669 if (node == nullptr) {
670 /* Disable existing active viewer. */
671 WorkSpace *workspace = CTX_wm_workspace(C);
674 }
675 }
676
677 if (!(changed || found)) {
678 return false;
679 }
680
681 bool active_texture_changed = false;
682 bool viewer_node_changed = false;
683 if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) {
684 viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER;
685 ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
686 }
687 else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
688 viewer_path::activate_geometry_node(bmain, snode, *node);
689 }
692 if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) ||
693 viewer_node_changed)
694 {
696 }
697
700
701 return true;
702}
703
705{
706 /* Get settings from RNA properties for operator. */
707 int2 mval;
708 RNA_int_get_array(op->ptr, "location", mval);
709
712
713 /* Perform the selection. */
714 const bool changed = node_mouse_select(C, op, mval, &params);
715
716 if (changed) {
718 }
719 /* Nothing selected, just pass through. */
721}
722
723static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
724{
725 RNA_int_set_array(op->ptr, "location", event->mval);
726
727 const int retval = node_select_exec(C, op);
728
730}
731
733{
734 PropertyRNA *prop;
735
736 /* identifiers */
737 ot->name = "Select";
738 ot->idname = "NODE_OT_select";
739 ot->description = "Select the node under the cursor";
740
741 /* api callbacks */
746
747 /* flags */
749
750 /* properties */
752
753 prop = RNA_def_int_vector(ot->srna,
754 "location",
755 2,
756 nullptr,
757 INT_MIN,
758 INT_MAX,
759 "Location",
760 "Mouse location",
761 INT_MIN,
762 INT_MAX);
764
765 RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
766
768 "clear_viewer",
769 false,
770 "Clear Viewer",
771 "Deactivate geometry nodes viewer when clicking in empty space");
772}
773
776/* -------------------------------------------------------------------- */
781{
782 SpaceNode &snode = *CTX_wm_space_node(C);
783 bNodeTree &node_tree = *snode.edittree;
784 const ARegion &region = *CTX_wm_region(C);
785 rctf rectf;
786
788 UI_view2d_region_to_view_rctf(&region.v2d, &rectf, &rectf);
789
790 const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
791 const bool select = (sel_op != SEL_OP_SUB);
792 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
794 }
795
796 for (bNode *node : node_tree.all_nodes()) {
797 bool is_inside = false;
798
799 switch (node->type) {
800 case NODE_FRAME: {
801 /* Frame nodes are selectable by their borders (including their whole rect - as for other
802 * nodes - would prevent selection of other nodes inside that frame. */
803 const rctf frame_inside = node_frame_rect_inside(snode, *node);
804 if (BLI_rctf_isect(&rectf, &node->runtime->totr, nullptr) &&
805 !BLI_rctf_inside_rctf(&frame_inside, &rectf))
806 {
808 is_inside = true;
809 }
810 break;
811 }
812 default: {
813 is_inside = BLI_rctf_isect(&rectf, &node->runtime->totr, nullptr);
814 break;
815 }
816 }
817
818 if (is_inside) {
820 }
821 }
822
824
826
827 return OPERATOR_FINISHED;
828}
829
830static int node_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
831{
832 const bool tweak = RNA_boolean_get(op->ptr, "tweak");
833
834 if (tweak && is_event_over_node_or_socket(*C, *event)) {
836 }
837
838 return WM_gesture_box_invoke(C, op, event);
839}
840
842{
843 /* identifiers */
844 ot->name = "Box Select";
845 ot->idname = "NODE_OT_select_box";
846 ot->description = "Use box selection to select nodes";
847
848 /* api callbacks */
853
855
856 /* flags */
858
859 /* properties */
861 "tweak",
862 false,
863 "Tweak",
864 "Only activate when mouse is not over a node (useful for tweak gesture)");
865
868}
869
872/* -------------------------------------------------------------------- */
877{
878 SpaceNode *snode = CTX_wm_space_node(C);
879 ARegion *region = CTX_wm_region(C);
880 bNodeTree &node_tree = *snode->edittree;
881
882 int x, y, radius;
883 float2 offset;
884
885 float zoom = float(BLI_rcti_size_x(&region->winrct)) / float(BLI_rctf_size_x(&region->v2d.cur));
886
887 const eSelectOp sel_op = ED_select_op_modal(
888 (eSelectOp)RNA_enum_get(op->ptr, "mode"),
890 const bool select = (sel_op != SEL_OP_SUB);
891 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
893 }
894
895 /* get operator properties */
896 x = RNA_int_get(op->ptr, "x");
897 y = RNA_int_get(op->ptr, "y");
898 radius = RNA_int_get(op->ptr, "radius");
899
900 UI_view2d_region_to_view(&region->v2d, x, y, &offset.x, &offset.y);
901
902 for (bNode *node : node_tree.all_nodes()) {
903 switch (node->type) {
904 case NODE_FRAME: {
905 /* Frame nodes are selectable by their borders (including their whole rect - as for other
906 * nodes - would prevent selection of _only_ other nodes inside that frame. */
907 rctf frame_inside = node_frame_rect_inside(*snode, *node);
908 const float radius_adjusted = float(radius) / zoom;
909 BLI_rctf_pad(&frame_inside, -2.0f * radius_adjusted, -2.0f * radius_adjusted);
910 if (BLI_rctf_isect_circle(&node->runtime->totr, offset, radius_adjusted) &&
911 !BLI_rctf_isect_circle(&frame_inside, offset, radius_adjusted))
912 {
914 }
915 break;
916 }
917 default: {
918 if (BLI_rctf_isect_circle(&node->runtime->totr, offset, radius / zoom)) {
920 }
921 break;
922 }
923 }
924 }
925
927
928 return OPERATOR_FINISHED;
929}
930
932{
933 /* identifiers */
934 ot->name = "Circle Select";
935 ot->idname = "NODE_OT_select_circle";
936 ot->description = "Use circle selection to select nodes";
937
938 /* api callbacks */
944
945 /* flags */
947
948 /* properties */
951}
952
955/* -------------------------------------------------------------------- */
959static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
960{
961 const bool tweak = RNA_boolean_get(op->ptr, "tweak");
962
963 if (tweak && is_event_over_node_or_socket(*C, *event)) {
965 }
966
967 return WM_gesture_lasso_invoke(C, op, event);
968}
969
970static bool do_lasso_select_node(bContext *C, const Span<int2> mcoords, eSelectOp sel_op)
971{
972 SpaceNode *snode = CTX_wm_space_node(C);
973 bNodeTree &node_tree = *snode->edittree;
974
975 ARegion *region = CTX_wm_region(C);
976
977 rcti rect;
978 bool changed = false;
979
980 const bool select = (sel_op != SEL_OP_SUB);
981 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
983 changed = true;
984 }
985
986 /* Get rectangle from operator. */
987 BLI_lasso_boundbox(&rect, mcoords);
988
989 for (bNode *node : node_tree.all_nodes()) {
990 if (select && (node->flag & NODE_SELECT)) {
991 continue;
992 }
993
994 switch (node->type) {
995 case NODE_FRAME: {
996 /* Frame nodes are selectable by their borders (including their whole rect - as for other
997 * nodes - would prevent selection of other nodes inside that frame. */
998 rctf rectf;
999 BLI_rctf_rcti_copy(&rectf, &rect);
1000 UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
1001 const rctf frame_inside = node_frame_rect_inside(*snode, *node);
1002 if (BLI_rctf_isect(&rectf, &node->runtime->totr, nullptr) &&
1003 !BLI_rctf_inside_rctf(&frame_inside, &rectf))
1004 {
1006 changed = true;
1007 }
1008 break;
1009 }
1010 default: {
1011 int2 screen_co;
1012 const float2 center = {BLI_rctf_cent_x(&node->runtime->totr),
1013 BLI_rctf_cent_y(&node->runtime->totr)};
1014
1015 /* marker in screen coords */
1017 &region->v2d, center.x, center.y, &screen_co.x, &screen_co.y) &&
1018 BLI_rcti_isect_pt(&rect, screen_co.x, screen_co.y) &&
1019 BLI_lasso_is_point_inside(mcoords, screen_co.x, screen_co.y, INT_MAX))
1020 {
1022 changed = true;
1023 }
1024 break;
1025 }
1026 }
1027 }
1028
1029 if (changed) {
1031 }
1032
1033 return changed;
1034}
1035
1037{
1038 const Array<int2> mcoords = WM_gesture_lasso_path_to_array(C, op);
1039
1040 if (mcoords.is_empty()) {
1041 return OPERATOR_PASS_THROUGH;
1042 }
1043
1044 const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
1045
1046 do_lasso_select_node(C, mcoords, sel_op);
1047
1048 return OPERATOR_FINISHED;
1049}
1050
1052{
1053 /* identifiers */
1054 ot->name = "Lasso Select";
1055 ot->description = "Select nodes using lasso selection";
1056 ot->idname = "NODE_OT_select_lasso";
1057
1058 /* api callbacks */
1064
1065 /* flags */
1067
1068 /* properties */
1070 "tweak",
1071 false,
1072 "Tweak",
1073 "Only activate when mouse is not over a node (useful for tweak gesture)");
1074
1077}
1078
1081/* -------------------------------------------------------------------- */
1086{
1087 for (const bNode *node : node_tree.all_nodes()) {
1088 if (node->flag & NODE_SELECT) {
1089 return true;
1090 }
1091 }
1092 return false;
1093}
1094
1096{
1097 SpaceNode &snode = *CTX_wm_space_node(C);
1098 bNodeTree &node_tree = *snode.edittree;
1099
1100 node_tree.ensure_topology_cache();
1101
1102 int action = RNA_enum_get(op->ptr, "action");
1103 if (action == SEL_TOGGLE) {
1105 action = SEL_DESELECT;
1106 }
1107 else {
1108 action = SEL_SELECT;
1109 }
1110 }
1111
1112 switch (action) {
1113 case SEL_SELECT:
1114 for (bNode *node : node_tree.all_nodes()) {
1115 bke::node_set_selected(node, true);
1116 }
1117 break;
1118 case SEL_DESELECT:
1120 break;
1121 case SEL_INVERT:
1122 for (bNode *node : node_tree.all_nodes()) {
1123 bke::node_set_selected(node, !(node->flag & SELECT));
1124 }
1125 break;
1126 }
1127
1129
1132 return OPERATOR_FINISHED;
1133}
1134
1136{
1137 /* identifiers */
1138 ot->name = "(De)select All";
1139 ot->description = "(De)select all nodes";
1140 ot->idname = "NODE_OT_select_all";
1141
1142 /* api callbacks */
1145
1146 /* flags */
1148
1150}
1151
1154/* -------------------------------------------------------------------- */
1159{
1160 SpaceNode &snode = *CTX_wm_space_node(C);
1161 bNodeTree &node_tree = *snode.edittree;
1162
1163 node_tree.ensure_topology_cache();
1164
1165 VectorSet<bNode *> initial_selection = get_selected_nodes(node_tree);
1166
1167 for (bNode *node : initial_selection) {
1168 for (bNodeSocket *output_socket : node->output_sockets()) {
1169 if (!output_socket->is_available()) {
1170 continue;
1171 }
1172 for (bNodeSocket *input_socket : output_socket->directly_linked_sockets()) {
1173 if (!input_socket->is_available()) {
1174 continue;
1175 }
1176 bke::node_set_selected(&input_socket->owner_node(), true);
1177 }
1178 }
1179 }
1180
1182
1184 return OPERATOR_FINISHED;
1185}
1186
1188{
1189 /* identifiers */
1190 ot->name = "Select Linked To";
1191 ot->description = "Select nodes linked to the selected ones";
1192 ot->idname = "NODE_OT_select_linked_to";
1193
1194 /* api callbacks */
1197
1198 /* flags */
1200}
1201
1204/* -------------------------------------------------------------------- */
1209{
1210 SpaceNode &snode = *CTX_wm_space_node(C);
1211 bNodeTree &node_tree = *snode.edittree;
1212
1213 node_tree.ensure_topology_cache();
1214
1215 VectorSet<bNode *> initial_selection = get_selected_nodes(node_tree);
1216
1217 for (bNode *node : initial_selection) {
1218 for (bNodeSocket *input_socket : node->input_sockets()) {
1219 if (!input_socket->is_available()) {
1220 continue;
1221 }
1222 for (bNodeSocket *output_socket : input_socket->directly_linked_sockets()) {
1223 if (!output_socket->is_available()) {
1224 continue;
1225 }
1226 bke::node_set_selected(&output_socket->owner_node(), true);
1227 }
1228 }
1229 }
1230
1232
1234 return OPERATOR_FINISHED;
1235}
1236
1238{
1239 /* identifiers */
1240 ot->name = "Select Linked From";
1241 ot->description = "Select nodes linked from the selected ones";
1242 ot->idname = "NODE_OT_select_linked_from";
1243
1244 /* api callbacks */
1247
1248 /* flags */
1250}
1251
1254/* -------------------------------------------------------------------- */
1258static bool nodes_are_same_type_for_select(const bNode &a, const bNode &b)
1259{
1260 return a.type == b.type;
1261}
1262
1264{
1265 SpaceNode *snode = CTX_wm_space_node(C);
1266 ARegion *region = CTX_wm_region(C);
1267 const bool prev = RNA_boolean_get(op->ptr, "prev");
1268 bNode *active_node = bke::node_get_active(snode->edittree);
1269
1270 if (active_node == nullptr) {
1271 return OPERATOR_CANCELLED;
1272 }
1273
1274 bNodeTree &node_tree = *snode->edittree;
1275 node_tree.ensure_topology_cache();
1276 if (node_tree.all_nodes().size() == 1) {
1277 return OPERATOR_CANCELLED;
1278 }
1279
1280 const Span<const bNode *> toposort = node_tree.toposort_left_to_right();
1281 const int index = toposort.first_index(active_node);
1282
1283 int new_index = index;
1284 while (true) {
1285 new_index += (prev ? -1 : 1);
1286 if (!toposort.index_range().contains(new_index)) {
1287 return OPERATOR_CANCELLED;
1288 }
1289 if (nodes_are_same_type_for_select(*toposort[new_index], *active_node)) {
1290 break;
1291 }
1292 }
1293
1294 bNode *new_active_node = node_tree.all_nodes()[toposort[new_index]->index()];
1295 if (new_active_node == active_node) {
1296 return OPERATOR_CANCELLED;
1297 }
1298
1299 node_select_single(*C, *new_active_node);
1300
1301 if (!BLI_rctf_inside_rctf(&region->v2d.cur, &new_active_node->runtime->totr)) {
1302 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
1303 space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx);
1304 }
1305
1306 return OPERATOR_FINISHED;
1307}
1308
1310{
1311 /* identifiers */
1312 ot->name = "Activate Same Type Next/Prev";
1313 ot->description = "Activate and view same node type, step by step";
1314 ot->idname = "NODE_OT_select_same_type_step";
1315
1316 /* api callbacks */
1319
1320 /* flags */
1322
1323 RNA_def_boolean(ot->srna, "prev", false, "Previous", "");
1324}
1325
1328/* -------------------------------------------------------------------- */
1332static void node_find_create_label(const bNode *node, char *str, int str_maxncpy)
1333{
1334 if (node->label[0]) {
1335 BLI_snprintf(str, str_maxncpy, "%s (%s)", node->name, node->label);
1336 }
1337 else {
1338 BLI_strncpy(str, node->name, str_maxncpy);
1339 }
1340}
1341
1342/* Generic search invoke. */
1343static void node_find_update_fn(const bContext *C,
1344 void * /*arg*/,
1345 const char *str,
1346 uiSearchItems *items,
1347 const bool /*is_first*/)
1348{
1349 SpaceNode *snode = CTX_wm_space_node(C);
1350
1352
1353 for (bNode *node : snode->edittree->all_nodes()) {
1354 char name[256];
1355 node_find_create_label(node, name, ARRAY_SIZE(name));
1356 search.add(name, node);
1357 }
1358
1359 const Vector<bNode *> filtered_nodes = search.query(str);
1360
1361 for (bNode *node : filtered_nodes) {
1362 char name[256];
1363 node_find_create_label(node, name, ARRAY_SIZE(name));
1364 if (!UI_search_item_add(items, name, node, ICON_NONE, 0, 0)) {
1365 break;
1366 }
1367 }
1368}
1369
1370static void node_find_exec_fn(bContext *C, void * /*arg1*/, void *arg2)
1371{
1372 SpaceNode *snode = CTX_wm_space_node(C);
1373 bNode *active = (bNode *)arg2;
1374
1375 if (active) {
1376 ARegion *region = CTX_wm_region(C);
1377 node_select_single(*C, *active);
1378
1379 if (!BLI_rctf_inside_rctf(&region->v2d.cur, &active->runtime->totr)) {
1380 space_node_view_flag(*C, *snode, *region, NODE_SELECT, U.smooth_viewtx);
1381 }
1382 }
1383}
1384
1385static uiBlock *node_find_menu(bContext *C, ARegion *region, void *arg_optype)
1386{
1387 static char search[256] = "";
1388 uiBlock *block;
1389 uiBut *but;
1390 wmOperatorType *optype = (wmOperatorType *)arg_optype;
1391
1392 block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
1395
1396 but = uiDefSearchBut(block,
1397 search,
1398 0,
1399 ICON_VIEWZOOM,
1400 sizeof(search),
1401 10,
1402 10,
1404 UI_UNIT_Y,
1405 "");
1407 but, nullptr, node_find_update_fn, optype, false, nullptr, node_find_exec_fn, nullptr);
1409
1410 /* Fake button holds space for search items. */
1411 uiDefBut(block,
1413 0,
1414 "",
1415 10,
1416 10 - UI_searchbox_size_y(),
1419 nullptr,
1420 0,
1421 0,
1422 nullptr);
1423
1424 /* Move it downwards, mouse over button. */
1425 std::array<int, 2> bounds_offset = {0, -UI_UNIT_Y};
1426 UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, bounds_offset.data());
1427
1428 return block;
1429}
1430
1431static int node_find_node_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1432{
1433 UI_popup_block_invoke(C, node_find_menu, op->type, nullptr);
1434 return OPERATOR_CANCELLED;
1435}
1436
1438{
1439 /* identifiers */
1440 ot->name = "Find Node";
1441 ot->description = "Search for a node by name and focus and select it";
1442 ot->idname = "NODE_OT_find_node";
1443
1444 /* api callbacks */
1447
1448 /* flags */
1450}
1451
1454} // namespace blender::ed::space_node
WorkSpace * CTX_wm_workspace(const bContext *C)
SpaceNode * CTX_wm_space_node(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define NODE_REROUTE
Definition BKE_node.hh:804
#define NODE_FRAME
Definition BKE_node.hh:803
void BKE_viewer_path_clear(ViewerPath *viewer_path)
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
bool BLI_lasso_is_point_inside(blender::Span< blender::int2 > mcoords, int sx, int sy, int error_value)
void BLI_lasso_boundbox(rcti *rect, blender::Span< blender::int2 > mcoords)
#define LISTBASE_FOREACH(type, var, list)
MINLINE float square_f(float a)
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:184
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest)
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:180
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], float radius)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
Definition rct.c:631
bool BLI_rctf_isect_pt(const struct rctf *rect, float x, float y)
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b)
Definition rct.c:193
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t size_t size_t BLI_str_partition_ex_utf8(const char *str, const char *end, const unsigned int delim[], const char **r_sep, const char **r_suf, bool from_right) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
unsigned int uint
#define ARRAY_SIZE(arr)
#define STREQLEN(a, b, n)
#define STREQ(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ NODE_DO_OUTPUT
@ NODE_ACTIVE
@ NODE_SELECT
@ SOCK_OUT
@ SOCK_IN
@ SPACE_VIEW3D
@ OPERATOR_PASS_THROUGH
void ED_node_set_active(Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
Definition node_edit.cc:722
void ED_node_set_active_viewer_key(SpaceNode *snode)
bool ED_operator_node_active(bContext *C)
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first)
#define SEL_OP_USE_PRE_DESELECT(sel_op)
std::string ED_select_circle_get_name(wmOperatorType *ot, PointerRNA *ptr)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
void ED_select_pick_params_from_operator(PointerRNA *ptr, SelectPick_Params *params) ATTR_NONNULL(1
void std::string ED_select_pick_get_name(wmOperatorType *ot, PointerRNA *ptr)
eSelectOp
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
@ SEL_OP_AND
@ SEL_OP_XOR
bool ED_view3d_has_workbench_in_texture_color(const Scene *scene, const Object *ob, const View3D *v3d)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
#define UI_UNIT_Y
@ UI_EMBOSS
void UI_block_theme_style_set(uiBlock *block, char theme_style)
@ UI_BLOCK_SEARCH_MENU
@ UI_BLOCK_LOOP
@ UI_BLOCK_MOVEMOUSE_QUIT
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:590
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
int UI_searchbox_size_x()
int UI_searchbox_size_y()
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, const char *tip)
@ UI_BLOCK_THEME_STYLE_POPUP
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_LABEL
void UI_but_flag_enable(uiBut *but, int flag)
@ UI_BUT_ACTIVATE_ON_INIT
bool UI_view2d_view_to_region_clip(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1697
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1663
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1670
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_NODE
Definition WM_types.hh:361
#define NC_VIEWER_PATH
Definition WM_types.hh:373
#define ND_NODE_GIZMO
Definition WM_types.hh:482
#define NA_SELECTED
Definition WM_types.hh:555
unsigned int U
Definition btGjkEpa3.h:78
bool is_empty() const
Definition BLI_array.hh:253
constexpr bool contains(int64_t value) const
constexpr int64_t first_index(const T &search_value) const
Definition BLI_span.hh:378
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
bool add(const Key &key)
void add(const StringRef str, T *user_data, const int weight=0)
Vector< T * > query(const StringRef query) const
local_group_size(16, 16) .push_constant(Type b
#define SELECT
OperationNode * node
draw_view in_light_buf[] float
#define str(s)
static bool is_inside(int x, int y, int cols, int rows)
Definition filesel.cc:768
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
bNode * node_get_active(bNodeTree *ntree)
Definition node.cc:3849
Span< const bNodeZoneType * > all_zone_types()
bool node_set_selected(bNode *node, bool select)
Definition node.cc:3863
static bool has_workbench_in_texture_color(const wmWindowManager *wm, const Scene *scene, const Object *ob)
static uiBlock * node_find_menu(bContext *C, ARegion *region, void *arg_optype)
static bool node_select_grouped_type(bNodeTree &node_tree, bNode &node_act)
rctf node_frame_rect_inside(const SpaceNode &snode, const bNode &node)
void node_deselect_all_input_sockets(bNodeTree &node_tree, bool deselect_nodes)
static void node_find_exec_fn(bContext *C, void *, void *arg2)
void NODE_OT_select_circle(wmOperatorType *ot)
static bool is_position_over_node_or_socket(SpaceNode &snode, ARegion &region, const float2 &mouse)
static int node_box_select_exec(bContext *C, wmOperator *op)
void tree_draw_order_update(bNodeTree &ntree)
Definition node_draw.cc:302
static int node_lasso_select_exec(bContext *C, wmOperator *op)
static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
bool space_node_view_flag(bContext &C, SpaceNode &snode, ARegion &region, int node_flag, int smooth_viewtx)
Definition node_view.cc:76
static bool node_mouse_select(bContext *C, wmOperator *op, const int2 mval, SelectPick_Params *params)
static bool do_lasso_select_node(bContext *C, const Span< int2 > mcoords, eSelectOp sel_op)
void node_select_paired(bNodeTree &node_tree)
void NODE_OT_find_node(wmOperatorType *ot)
static void node_find_update_fn(const bContext *C, void *, const char *str, uiSearchItems *items, const bool)
void NODE_OT_select_lasso(wmOperatorType *ot)
bool node_deselect_all(bNodeTree &node_tree)
void node_socket_select(bNode *node, bNodeSocket &sock)
bNodeSocket * node_find_indicated_socket(SpaceNode &snode, ARegion &region, const float2 &cursor, const eNodeSocketInOut in_out)
void NODE_OT_select(wmOperatorType *ot)
static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right)
Array< bNode * > tree_draw_order_calc_nodes_reversed(bNodeTree &ntree)
Definition node_draw.cc:326
static void node_socket_toggle(bNode *node, bNodeSocket &sock, bool deselect_node)
static bool nodes_are_same_type_for_select(const bNode &a, const bNode &b)
void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node)
static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int node_find_node_invoke(bContext *C, wmOperator *op, const wmEvent *)
void NODE_OT_select_grouped(wmOperatorType *ot)
static int node_circleselect_exec(bContext *C, wmOperator *op)
static int node_select_all_exec(bContext *C, wmOperator *op)
static void node_find_create_label(const bNode *node, char *str, int str_maxncpy)
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
void NODE_OT_select_linked_from(wmOperatorType *ot)
void node_deselect_all_output_sockets(bNodeTree &node_tree, bool deselect_nodes)
static int node_select_grouped_exec(bContext *C, wmOperator *op)
static bNode * node_under_mouse_select(const SpaceNode &snode, const float2 mouse)
static int node_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void NODE_OT_select_same_type_step(wmOperatorType *ot)
static int node_select_linked_to_exec(bContext *C, wmOperator *)
void node_select_single(bContext &C, bNode &node)
static bool node_select_grouped_color(bNodeTree &node_tree, bNode &node_act)
void NODE_OT_select_linked_to(wmOperatorType *ot)
static bool any_node_selected(const bNodeTree &node_tree)
bool node_or_socket_isect_event(const bContext &C, const wmEvent &event)
static bool node_under_mouse_tweak(const SpaceNode &snode, const float2 &mouse)
static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float2 node_to_view(const bNode &node, const float2 &co)
Definition node_draw.cc:354
static bool is_event_over_node_or_socket(const bContext &C, const wmEvent &event)
static bool node_frame_select_isect_mouse(const SpaceNode &snode, const bNode &node, const float2 &mouse)
void NODE_OT_select_box(wmOperatorType *ot)
void NODE_OT_select_all(wmOperatorType *ot)
static int node_select_exec(bContext *C, wmOperator *op)
static int node_select_linked_from_exec(bContext *C, wmOperator *)
void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T max(const T &a, const T &b)
#define NODE_RESIZE_MARGIN
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
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_int_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const int *default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int 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)
SpaceNode_Runtime * runtime
struct bNodeTree * edittree
ViewerPath viewer_path
float color[3]
char name[64]
bNodeRuntimeHandle * runtime
int16_t type
float xmin
int mval[2]
Definition WM_types.hh:728
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
std::string(* get_name)(wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1068
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_gesture_is_modal_first(const wmGesture *gesture)
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Array< int2 > WM_gesture_lasso_path_to_array(bContext *, wmOperator *op)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(wmOperator *op, rctf *r_rect)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operator_properties_mouse_select(wmOperatorType *ot)
int WM_operator_flag_only_pass_through_on_press(int retval, const wmEvent *event)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_operator_smooth_viewtx_get(const wmOperator *op)