Fix for #34739 and #35060, avoid ambiguity in compositor viewer nodes.
[blender.git] / source / blender / editors / space_node / node_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation, Nathan Letwory
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_node/node_select.c
28  *  \ingroup spnode
29  */
30
31 #include <stdlib.h>
32
33 #include "DNA_node_types.h"
34
35 #include "BLI_rect.h"
36 #include "BLI_lasso.h"
37 #include "BLI_string.h"
38 #include "BLI_utildefines.h"
39
40 #include "BKE_context.h"
41 #include "BKE_main.h"
42 #include "BKE_node.h"
43
44 #include "ED_node.h"  /* own include */
45 #include "ED_screen.h"
46 #include "ED_types.h"
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
57
58 #include "MEM_guardedalloc.h"
59
60 #include "node_intern.h"  /* own include */
61
62 /* ****** helpers ****** */
63
64 static bNode *node_under_mouse_select(bNodeTree *ntree, int mx, int my)
65 {
66         bNode *node;
67         
68         for (node = ntree->nodes.last; node; node = node->prev) {
69                 if (node->typeinfo->select_area_func) {
70                         if (node->typeinfo->select_area_func(node, mx, my))
71                                 return node;
72                 }
73         }
74         return NULL;
75 }
76
77 static bNode *node_under_mouse_tweak(bNodeTree *ntree, int mx, int my)
78 {
79         bNode *node;
80         
81         for (node = ntree->nodes.last; node; node = node->prev) {
82                 if (node->typeinfo->tweak_area_func) {
83                         if (node->typeinfo->tweak_area_func(node, mx, my))
84                                 return node;
85                 }
86         }
87         return NULL;
88 }
89
90 static void node_toggle(bNode *node)
91 {
92         nodeSetSelected(node, !(node->flag & SELECT));
93 }
94
95 void node_socket_select(bNode *node, bNodeSocket *sock)
96 {
97         sock->flag |= SELECT;
98         
99         /* select node too */
100         if (node)
101                 node->flag |= SELECT;
102 }
103
104 void node_socket_deselect(bNode *node, bNodeSocket *sock, int deselect_node)
105 {
106         sock->flag &= ~SELECT;
107         
108         if (node && deselect_node) {
109                 int sel = 0;
110                 
111                 /* if no selected sockets remain, also deselect the node */
112                 for (sock = node->inputs.first; sock; sock = sock->next) {
113                         if (sock->flag & SELECT) {
114                                 sel = 1;
115                                 break;
116                         }
117                 }
118                 for (sock = node->outputs.first; sock; sock = sock->next) {
119                         if (sock->flag & SELECT) {
120                                 sel = 1;
121                                 break;
122                         }
123                 }
124                 
125                 if (!sel)
126                         node->flag &= ~SELECT;
127         }
128 }
129
130 static void node_socket_toggle(bNode *node, bNodeSocket *sock, int deselect_node)
131 {
132         if (sock->flag & SELECT)
133                 node_socket_deselect(node, sock, deselect_node);
134         else
135                 node_socket_select(node, sock);
136 }
137
138 /* no undo here! */
139 void node_deselect_all(SpaceNode *snode)
140 {
141         bNode *node;
142         
143         for (node = snode->edittree->nodes.first; node; node = node->next)
144                 nodeSetSelected(node, FALSE);
145 }
146
147 void node_deselect_all_input_sockets(SpaceNode *snode, int deselect_nodes)
148 {
149         bNode *node;
150         bNodeSocket *sock;
151         
152         /* XXX not calling node_socket_deselect here each time, because this does iteration
153          * over all node sockets internally to check if the node stays selected.
154          * We can do that more efficiently here.
155          */
156         
157         for (node = snode->edittree->nodes.first; node; node = node->next) {
158                 int sel = 0;
159                 
160                 for (sock = node->inputs.first; sock; sock = sock->next)
161                         sock->flag &= ~SELECT;
162                 
163                 /* if no selected sockets remain, also deselect the node */
164                 if (deselect_nodes) {
165                         for (sock = node->outputs.first; sock; sock = sock->next) {
166                                 if (sock->flag & SELECT) {
167                                         sel = 1;
168                                         break;
169                                 }
170                         }
171                         
172                         if (!sel)
173                                 node->flag &= ~SELECT;
174                 }
175         }
176 }
177
178 void node_deselect_all_output_sockets(SpaceNode *snode, int deselect_nodes)
179 {
180         bNode *node;
181         bNodeSocket *sock;
182         
183         /* XXX not calling node_socket_deselect here each time, because this does iteration
184          * over all node sockets internally to check if the node stays selected.
185          * We can do that more efficiently here.
186          */
187         
188         for (node = snode->edittree->nodes.first; node; node = node->next) {
189                 int sel = 0;
190                 
191                 for (sock = node->outputs.first; sock; sock = sock->next)
192                         sock->flag &= ~SELECT;
193                 
194                 /* if no selected sockets remain, also deselect the node */
195                 if (deselect_nodes) {
196                         for (sock = node->inputs.first; sock; sock = sock->next) {
197                                 if (sock->flag & SELECT) {
198                                         sel = 1;
199                                         break;
200                                 }
201                         }
202                         
203                         if (!sel)
204                                 node->flag &= ~SELECT;
205                 }
206         }
207 }
208
209 /* return 1 if we need redraw otherwise zero. */
210 int node_select_same_type(SpaceNode *snode)
211 {
212         bNode *nac, *p;
213         int redraw;
214
215         /* search for the active node. */
216         for (nac = snode->edittree->nodes.first; nac; nac = nac->next) {
217                 if (nac->flag & SELECT)
218                         break;
219         }
220
221         /* no active node, return. */
222         if (!nac)
223                 return(0);
224
225         redraw = 0;
226         for (p = snode->edittree->nodes.first; p; p = p->next) {
227                 if (p->type != nac->type && p->flag & SELECT) {
228                         /* if it's selected but different type, unselect */
229                         redraw = 1;
230                         nodeSetSelected(p, FALSE);
231                 }
232                 else if (p->type == nac->type && (!(p->flag & SELECT))) {
233                         /* if it's the same type and is not selected, select! */
234                         redraw = 1;
235                         nodeSetSelected(p, TRUE);
236                 }
237         }
238         return(redraw);
239 }
240
241 /* return 1 if we need redraw, otherwise zero.
242  * dir can be 0 == next or 0 != prev.
243  */
244 int node_select_same_type_np(SpaceNode *snode, int dir)
245 {
246         bNode *nac, *p, *tnode;
247
248         /* search the active one. */
249         for (nac = snode->edittree->nodes.first; nac; nac = nac->next) {
250                 if (nac->flag & SELECT)
251                         break;
252         }
253
254         /* no active node, return. */
255         if (!nac)
256                 return(0);
257
258         if (dir == 0)
259                 p = nac->next;
260         else
261                 p = nac->prev;
262
263         while (p) {
264                 /* Now search the next with the same type. */
265                 if (p->type == nac->type)
266                         break;
267
268                 if (dir == 0)
269                         p = p->next;
270                 else
271                         p = p->prev;
272         }
273
274         if (p) {
275                 for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next)
276                         if (tnode != p)
277                                 nodeSetSelected(tnode, FALSE);
278                 nodeSetSelected(p, TRUE);
279                 return(1);
280         }
281         return(0);
282 }
283
284 void node_select_single(bContext *C, bNode *node)
285 {
286         Main *bmain = CTX_data_main(C);
287         SpaceNode *snode = CTX_wm_space_node(C);
288         bNode *tnode;
289         
290         for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next)
291                 if (tnode != node)
292                         nodeSetSelected(tnode, FALSE);
293         nodeSetSelected(node, TRUE);
294         
295         ED_node_set_active(bmain, snode->edittree, node);
296         ED_node_set_active_viewer_key(snode);
297         
298         ED_node_sort(snode->edittree);
299         
300         WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
301 }
302
303 /* ****** Click Select ****** */
304  
305 static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const int mval[2], short extend)
306 {
307         bNode *node, *tnode;
308         bNodeSocket *sock, *tsock;
309         float mx, my;
310         int selected = 0;
311         
312         /* get mouse coordinates in view2d space */
313         UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my);
314         /* node_find_indicated_socket uses snode->mx/my */
315         snode->cursor[0] = mx;
316         snode->cursor[1] = my;
317         
318         if (extend) {
319                 /* first do socket selection, these generally overlap with nodes.
320                  * socket selection only in extend mode.
321                  */
322                 if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
323                         node_socket_toggle(node, sock, 1);
324                         selected = 1;
325                 }
326                 else if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
327                         if (sock->flag & SELECT) {
328                                 node_socket_deselect(node, sock, 1);
329                         }
330                         else {
331                                 /* only allow one selected output per node, for sensible linking.
332                                  * allows selecting outputs from different nodes though.
333                                  */
334                                 if (node) {
335                                         for (tsock = node->outputs.first; tsock; tsock = tsock->next)
336                                                 node_socket_deselect(node, tsock, 1);
337                                 }
338                                 node_socket_select(node, sock);
339                         }
340                         selected = 1;
341                 }
342                 else {
343                         /* find the closest visible node */
344                         node = node_under_mouse_select(snode->edittree, mx, my);
345                         
346                         if (node) {
347                                 if ((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0) {
348                                         /* if node is selected but not active make it active
349                                          * before it'll be desleected
350                                          */
351                                         ED_node_set_active(bmain, snode->edittree, node);
352                                 }
353                                 else {
354                                         node_toggle(node);
355                                         ED_node_set_active(bmain, snode->edittree, node);
356                                 }
357
358                                 selected = 1;
359                         }
360                 }
361         }
362         else {  /* extend == 0 */
363                 
364                 /* find the closest visible node */
365                 node = node_under_mouse_select(snode->edittree, mx, my);
366                 
367                 if (node) {
368                         for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) {
369                                 nodeSetSelected(tnode, false);
370                         }
371                         nodeSetSelected(node, TRUE);
372                         ED_node_set_active(bmain, snode->edittree, node);
373                         selected = 1;
374                 }
375         }
376         
377         /* update node order */
378         if (selected) {
379                 ED_node_set_active_viewer_key(snode);
380                 ED_node_sort(snode->edittree);
381         }
382         
383         return selected;
384 }
385
386 static int node_select_exec(bContext *C, wmOperator *op)
387 {
388         Main *bmain = CTX_data_main(C);
389         SpaceNode *snode = CTX_wm_space_node(C);
390         ARegion *ar = CTX_wm_region(C);
391         int mval[2];
392         short extend;
393         
394         /* get settings from RNA properties for operator */
395         mval[0] = RNA_int_get(op->ptr, "mouse_x");
396         mval[1] = RNA_int_get(op->ptr, "mouse_y");
397         
398         extend = RNA_boolean_get(op->ptr, "extend");
399         
400         /* perform the select */
401         if (node_mouse_select(bmain, snode, ar, mval, extend)) {
402                 /* send notifiers */
403                 WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
404                 
405                 /* allow tweak event to work too */
406                 return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
407         }
408         else {
409                 /* allow tweak event to work too */
410                 return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
411         }
412 }
413
414 static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
415 {
416         RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
417         RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
418
419         return node_select_exec(C, op);
420 }
421
422
423 void NODE_OT_select(wmOperatorType *ot)
424 {
425         /* identifiers */
426         ot->name = "Select";
427         ot->idname = "NODE_OT_select";
428         ot->description = "Select the node under the cursor";
429         
430         /* api callbacks */
431         ot->invoke = node_select_invoke;
432         ot->poll = ED_operator_node_active;
433         
434         /* flags */
435         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
436         
437         /* properties */
438         RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
439         RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
440         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
441 }
442
443 /* ****** Border Select ****** */
444
445 static int node_borderselect_exec(bContext *C, wmOperator *op)
446 {
447         SpaceNode *snode = CTX_wm_space_node(C);
448         ARegion *ar = CTX_wm_region(C);
449         bNode *node;
450         rcti rect;
451         rctf rectf;
452         int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
453         int extend = RNA_boolean_get(op->ptr, "extend");
454         
455         WM_operator_properties_border_to_rcti(op, &rect);
456
457         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
458         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
459         
460         for (node = snode->edittree->nodes.first; node; node = node->next) {
461                 if (BLI_rctf_isect(&rectf, &node->totr, NULL)) {
462                         nodeSetSelected(node, (gesture_mode == GESTURE_MODAL_SELECT));
463                 }
464                 else if (!extend) {
465                         nodeSetSelected(node, FALSE);
466                 }
467         }
468         
469         ED_node_sort(snode->edittree);
470         
471         WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
472
473         return OPERATOR_FINISHED;
474 }
475
476 static int node_border_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
477 {
478         int tweak = RNA_boolean_get(op->ptr, "tweak");
479         
480         if (tweak) {
481                 /* prevent initiating the border select if the mouse is over a node */
482                 /* this allows border select on empty space, but drag-translate on nodes */
483                 SpaceNode *snode = CTX_wm_space_node(C);
484                 ARegion *ar = CTX_wm_region(C);
485                 float mx, my;
486
487                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &mx, &my);
488                 
489                 if (node_under_mouse_tweak(snode->edittree, mx, my))
490                         return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
491         }
492         
493         return WM_border_select_invoke(C, op, event);
494 }
495
496 void NODE_OT_select_border(wmOperatorType *ot)
497 {
498         /* identifiers */
499         ot->name = "Border Select";
500         ot->idname = "NODE_OT_select_border";
501         ot->description = "Use box selection to select nodes";
502         
503         /* api callbacks */
504         ot->invoke = node_border_select_invoke;
505         ot->exec = node_borderselect_exec;
506         ot->modal = WM_border_select_modal;
507         ot->cancel = WM_border_select_cancel;
508         
509         ot->poll = ED_operator_node_active;
510         
511         /* flags */
512         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
513         
514         /* rna */
515         WM_operator_properties_gesture_border(ot, TRUE);
516         RNA_def_boolean(ot->srna, "tweak", 0, "Tweak", "Only activate when mouse is not over a node - useful for tweak gesture");
517 }
518
519 /* ****** Lasso Select ****** */
520
521 static int do_lasso_select_node(bContext *C, const int mcords[][2], short moves, short select)
522 {
523         SpaceNode *snode = CTX_wm_space_node(C);
524         bNode *node;
525
526         ARegion *ar = CTX_wm_region(C);
527
528         rcti rect;
529         int change = FALSE;
530
531         /* get rectangle from operator */
532         BLI_lasso_boundbox(&rect, mcords, moves);
533
534         /* do actual selection */
535         for (node = snode->edittree->nodes.first; node; node = node->next) {
536                 int screen_co[2];
537                 const float cent[2] = {BLI_rctf_cent_x(&node->totr),
538                                        BLI_rctf_cent_y(&node->totr)};
539
540                 /* marker in screen coords */
541                 UI_view2d_view_to_region(&ar->v2d,
542                                          cent[0], cent[1],
543                                          &screen_co[0], &screen_co[1]);
544
545                 if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
546                         BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX))
547                 {
548                         nodeSetSelected(node, select);
549                         change = TRUE;
550                 }
551         }
552
553         if (change) {
554                 WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
555         }
556
557         return change;
558 }
559
560 static int node_lasso_select_exec(bContext *C, wmOperator *op)
561 {
562         int mcords_tot;
563         const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
564
565         if (mcords) {
566                 short select;
567
568                 select = !RNA_boolean_get(op->ptr, "deselect");
569                 do_lasso_select_node(C, mcords, mcords_tot, select);
570
571                 MEM_freeN((void *)mcords);
572
573                 return OPERATOR_FINISHED;
574         }
575         return OPERATOR_PASS_THROUGH;
576 }
577
578 void NODE_OT_select_lasso(wmOperatorType *ot)
579 {
580         /* identifiers */
581         ot->name = "Lasso Select";
582         ot->description = "Select nodes using lasso selection";
583         ot->idname = "NODE_OT_select_lasso";
584
585         /* api callbacks */
586         ot->invoke = WM_gesture_lasso_invoke;
587         ot->modal = WM_gesture_lasso_modal;
588         ot->exec = node_lasso_select_exec;
589         ot->poll = ED_operator_node_active;
590         ot->cancel = WM_gesture_lasso_cancel;
591
592         /* flags */
593         ot->flag = OPTYPE_UNDO;
594
595         /* properties */
596         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
597         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
598         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
599 }
600
601 /* ****** Select/Deselect All ****** */
602
603 static int node_select_all_exec(bContext *C, wmOperator *op)
604 {
605         SpaceNode *snode = CTX_wm_space_node(C);
606         ListBase *node_lb = &snode->edittree->nodes;
607         bNode *node;
608         int action = RNA_enum_get(op->ptr, "action");
609
610         if (action == SEL_TOGGLE) {
611                 if (ED_node_select_check(node_lb))
612                         action = SEL_DESELECT;
613                 else
614                         action = SEL_SELECT;
615         }
616
617         for (node = node_lb->first; node; node = node->next) {
618                 switch (action) {
619                         case SEL_SELECT:
620                                 nodeSetSelected(node, TRUE);
621                                 break;
622                         case SEL_DESELECT:
623                                 nodeSetSelected(node, FALSE);
624                                 break;
625                         case SEL_INVERT:
626                                 nodeSetSelected(node, !(node->flag & SELECT));
627                                 break;
628                 }
629         }
630
631         ED_node_sort(snode->edittree);
632         
633         WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
634         return OPERATOR_FINISHED;
635 }
636
637 void NODE_OT_select_all(wmOperatorType *ot)
638 {
639         /* identifiers */
640         ot->name = "(De)select All";
641         ot->description = "(De)select all nodes";
642         ot->idname = "NODE_OT_select_all";
643         
644         /* api callbacks */
645         ot->exec = node_select_all_exec;
646         ot->poll = ED_operator_node_active;
647         
648         /* flags */
649         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
650
651         WM_operator_properties_select_all(ot);
652 }
653
654 /* ****** Select Linked To ****** */
655
656 static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
657 {
658         SpaceNode *snode = CTX_wm_space_node(C);
659         bNodeLink *link;
660         bNode *node;
661         
662         for (node = snode->edittree->nodes.first; node; node = node->next)
663                 node->flag &= ~NODE_TEST;
664
665         for (link = snode->edittree->links.first; link; link = link->next) {
666                 if (nodeLinkIsHidden(link))
667                         continue;
668                 if (link->fromnode && link->tonode && (link->fromnode->flag & NODE_SELECT))
669                         link->tonode->flag |= NODE_TEST;
670         }
671         
672         for (node = snode->edittree->nodes.first; node; node = node->next) {
673                 if (node->flag & NODE_TEST)
674                         nodeSetSelected(node, TRUE);
675         }
676         
677         ED_node_sort(snode->edittree);
678         
679         WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
680         return OPERATOR_FINISHED;
681 }
682
683 void NODE_OT_select_linked_to(wmOperatorType *ot)
684 {
685         /* identifiers */
686         ot->name = "Select Linked To";
687         ot->description = "Select nodes linked to the selected ones";
688         ot->idname = "NODE_OT_select_linked_to";
689         
690         /* api callbacks */
691         ot->exec = node_select_linked_to_exec;
692         ot->poll = ED_operator_node_active;
693         
694         /* flags */
695         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
696 }
697
698 /* ****** Select Linked From ****** */
699
700 static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
701 {
702         SpaceNode *snode = CTX_wm_space_node(C);
703         bNodeLink *link;
704         bNode *node;
705         
706         for (node = snode->edittree->nodes.first; node; node = node->next)
707                 node->flag &= ~NODE_TEST;
708
709         for (link = snode->edittree->links.first; link; link = link->next) {
710                 if (nodeLinkIsHidden(link))
711                         continue;
712                 if (link->fromnode && link->tonode && (link->tonode->flag & NODE_SELECT))
713                         link->fromnode->flag |= NODE_TEST;
714         }
715         
716         for (node = snode->edittree->nodes.first; node; node = node->next) {
717                 if (node->flag & NODE_TEST)
718                         nodeSetSelected(node, TRUE);
719         }
720         
721         ED_node_sort(snode->edittree);
722         
723         WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
724         return OPERATOR_FINISHED;
725 }
726
727 void NODE_OT_select_linked_from(wmOperatorType *ot)
728 {
729         /* identifiers */
730         ot->name = "Select Linked From";
731         ot->description = "Select nodes linked from the selected ones";
732         ot->idname = "NODE_OT_select_linked_from";
733         
734         /* api callbacks */
735         ot->exec = node_select_linked_from_exec;
736         ot->poll = ED_operator_node_active;
737         
738         /* flags */
739         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
740 }
741
742 /* ****** Select Same Type ****** */
743
744 static int node_select_same_type_exec(bContext *C, wmOperator *UNUSED(op))
745 {
746         SpaceNode *snode = CTX_wm_space_node(C);
747
748         node_select_same_type(snode);
749
750         ED_node_sort(snode->edittree);
751
752         WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
753         return OPERATOR_FINISHED;
754 }
755
756 void NODE_OT_select_same_type(wmOperatorType *ot)
757 {
758         /* identifiers */
759         ot->name = "Select Same Type";
760         ot->description = "Select all the nodes of the same type";
761         ot->idname = "NODE_OT_select_same_type";
762         
763         /* api callbacks */
764         ot->exec = node_select_same_type_exec;
765         ot->poll = ED_operator_node_active;
766         
767         /* flags */
768         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
769 }
770
771 /* ****** Select The Next/Prev Node Of The Same Type ****** */
772
773 /* ************************** */
774
775
776 static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
777 {
778         SpaceNode *snode = CTX_wm_space_node(C);
779         ARegion *ar = CTX_wm_region(C);
780         bNode **node_array;
781         bNode *active = nodeGetActive(snode->edittree);
782         int totnodes;
783         int revert = RNA_boolean_get(op->ptr, "prev");
784         int same_type = 1;
785         
786         ntreeGetDependencyList(snode->edittree, &node_array, &totnodes);
787         
788         if (totnodes > 1) {
789                 int a;
790                 
791                 for (a = 0; a < totnodes; a++) {
792                         if (node_array[a] == active)
793                                 break;
794                 }
795                 
796                 if (same_type) {
797                         bNode *node = NULL;
798                         
799                         while (node == NULL) {
800                                 if (revert) a--;
801                                 else a++;
802                                 
803                                 if (a < 0 || a >= totnodes)
804                                         break;
805                                 
806                                 node = node_array[a];
807                                 
808                                 if (node->type == active->type)
809                                         break;
810                                 else node = NULL;
811                         }
812                         if (node)
813                                 active = node;
814                 }
815                 else {
816                         if (revert) {
817                                 if (a == 0)
818                                         active = node_array[totnodes - 1];
819                                 else
820                                         active = node_array[a - 1];
821                         }
822                         else {
823                                 if (a == totnodes - 1)
824                                         active = node_array[0];
825                                 else
826                                         active = node_array[a + 1];
827                         }
828                 }
829                 
830                 node_select_single(C, active);
831
832                 /* is note outside view? */
833                 if (active->totr.xmax < ar->v2d.cur.xmin || active->totr.xmin > ar->v2d.cur.xmax ||
834                     active->totr.ymax < ar->v2d.cur.ymin || active->totr.ymin > ar->v2d.cur.ymax)
835                 {
836                         space_node_view_flag(C, snode, CTX_wm_region(C), NODE_SELECT);
837                 }
838         }
839         
840         if (node_array)
841                 MEM_freeN(node_array);
842         
843         return OPERATOR_FINISHED;
844 }
845
846 void NODE_OT_select_same_type_step(wmOperatorType *ot)
847 {
848         /* identifiers */
849         ot->name = "Activate Same Type Next/Prev";
850         ot->description = "Activate and view same node type, step by step";
851         ot->idname = "NODE_OT_select_same_type_step";
852         
853         /* api callbacks */
854         ot->exec = node_select_same_type_step_exec;
855         ot->poll = ED_operator_node_active;
856         
857         /* flags */
858         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
859         
860         RNA_def_boolean(ot->srna, "prev", 0, "Previous", "");
861
862 }
863
864 /* *************** find a node **************** */
865
866 /* generic  search invoke */
867 static void node_find_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
868 {
869         SpaceNode *snode = CTX_wm_space_node(C);
870         bNode *node;
871         
872         for (node = snode->edittree->nodes.first; node; node = node->next) {
873                 
874                 if (BLI_strcasestr(node->name, str) || BLI_strcasestr(node->label, str)) {
875                         char name[256];
876                         
877                         if (node->label[0])
878                                 BLI_snprintf(name, 256, "%s (%s)", node->name, node->label);
879                         else
880                                 BLI_strncpy(name, node->name, 256);
881                         if (false == uiSearchItemAdd(items, name, node, 0))
882                                 break;
883                 }
884         }
885 }
886
887 static void node_find_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2)
888 {
889         SpaceNode *snode = CTX_wm_space_node(C);
890         bNode *active = arg2;
891         
892         if (active) {
893                 ARegion *ar = CTX_wm_region(C);
894                 node_select_single(C, active);
895                 
896                 /* is note outside view? */
897                 if (active->totr.xmax < ar->v2d.cur.xmin || active->totr.xmin > ar->v2d.cur.xmax ||
898                     active->totr.ymax < ar->v2d.cur.ymin || active->totr.ymin > ar->v2d.cur.ymax)
899                 {
900                         space_node_view_flag(C, snode, ar, NODE_SELECT);
901                 }
902
903         }
904 }
905
906 static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
907 {
908         static char search[256] = "";
909         wmEvent event;
910         wmWindow *win = CTX_wm_window(C);
911         uiBlock *block;
912         uiBut *but;
913         wmOperator *op = (wmOperator *)arg_op;
914         
915         block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
916         uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
917         
918         but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9 * UI_UNIT_X, UI_UNIT_Y, 0, 0, "");
919         uiButSetSearchFunc(but, node_find_cb, op->type, node_find_call_cb, NULL);
920         
921         /* fake button, it holds space for search items */
922         uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
923         
924         uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
925         uiEndBlock(C, block);
926         
927         //      uiButActiveOnly(C, ar, block, but); XXX using this here makes Blender hang - investigate
928         event = *(win->eventstate);  /* XXX huh huh? make api call */
929         event.type = EVT_BUT_OPEN;
930         event.val = KM_PRESS;
931         event.customdata = but;
932         event.customdatafree = FALSE;
933         wm_event_add(win, &event);
934         
935         return block;
936 }
937
938
939 static int node_find_node_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
940 {
941         uiPupBlock(C, node_find_menu, op);
942         return OPERATOR_CANCELLED;
943 }
944
945
946 void NODE_OT_find_node(wmOperatorType *ot)
947 {
948         /* identifiers */
949         ot->name = "Find Node";
950         ot->description = "Search for named node and allow to select and activate it";
951         ot->idname = "NODE_OT_find_node";
952         
953         /* api callbacks */
954         ot->invoke = node_find_node_invoke;
955         ot->poll = ED_operator_node_active;
956         
957         /* flags */
958         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
959         
960         RNA_def_boolean(ot->srna, "prev", 0, "Previous", "");
961         
962 }
963
964