3d8b1676ea5621dab28f3d7b8100aa85b5bb5383
[blender.git] / source / blender / editors / space_node / node_select.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation, Nathan Letwory
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/editors/space_node/node_select.c
30  *  \ingroup spnode
31  */
32
33
34 #include <stdio.h>
35
36 #include "DNA_node_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "BKE_context.h"
40 #include "BKE_main.h"
41
42 #include "BLI_rect.h"
43 #include "BLI_utildefines.h"
44
45 #include "ED_node.h"
46 #include "ED_screen.h"
47 #include "ED_types.h"
48
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "UI_view2d.h"
56  
57 #include "node_intern.h"
58
59 /* ****** helpers ****** */
60
61 static bNode *node_under_mouse(bNodeTree *ntree, int mx, int my)
62 {
63         bNode *node;
64         
65         for(node=ntree->nodes.last; node; node=node->prev) {
66                 /* node body (header and scale are in other operators) */
67                 if (BLI_in_rctf(&node->totr, mx, my))
68                         return node;
69         }
70         return NULL;
71 }
72
73 /* ****** Click Select ****** */
74  
75 static bNode *node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const int mval[2], short extend)
76 {
77         bNode *node;
78         float mx, my;
79         
80         /* get mouse coordinates in view2d space */
81         mx= (float)mval[0];
82         my= (float)mval[1];
83         
84         UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my);
85         
86         /* find the closest visible node */
87         node = node_under_mouse(snode->edittree, mx, my);
88         
89         if (node) {
90                 if (extend == 0) {
91                         node_deselectall(snode);
92                         node->flag |= SELECT;
93                 }
94                 else
95                         node->flag ^= SELECT;
96                 
97                 ED_node_set_active(bmain, snode->edittree, node);
98                 
99                 node_sort(snode->edittree);
100         }
101
102         return node;
103 }
104
105 static int node_select_exec(bContext *C, wmOperator *op)
106 {
107         Main *bmain= CTX_data_main(C);
108         SpaceNode *snode= CTX_wm_space_node(C);
109         ARegion *ar= CTX_wm_region(C);
110         int mval[2];
111         short extend;
112         bNode *node= NULL;
113         
114         /* get settings from RNA properties for operator */
115         mval[0] = RNA_int_get(op->ptr, "mouse_x");
116         mval[1] = RNA_int_get(op->ptr, "mouse_y");
117         
118         extend = RNA_boolean_get(op->ptr, "extend");
119         
120         /* perform the select */
121         node= node_mouse_select(bmain, snode, ar, mval, extend);
122         
123         /* send notifiers */
124         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
125         
126         /* allow tweak event to work too */
127         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
128 }
129
130 static int node_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
131 {
132         RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
133         RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
134
135         return node_select_exec(C,op);
136 }
137
138
139 void NODE_OT_select(wmOperatorType *ot)
140 {
141         /* identifiers */
142         ot->name= "Select";
143         ot->idname= "NODE_OT_select";
144         ot->description= "Select node under cursor";
145         
146         /* api callbacks */
147         ot->invoke= node_select_invoke;
148         ot->poll= ED_operator_node_active;
149         
150         /* flags */
151         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
152         
153         /* properties */
154         RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
155         RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
156         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
157 }
158
159 /* ****** Border Select ****** */
160
161 static int node_borderselect_exec(bContext *C, wmOperator *op)
162 {
163         SpaceNode *snode= CTX_wm_space_node(C);
164         ARegion *ar= CTX_wm_region(C);
165         bNode *node;
166         rcti rect;
167         rctf rectf;
168         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
169         
170         rect.xmin= RNA_int_get(op->ptr, "xmin");
171         rect.ymin= RNA_int_get(op->ptr, "ymin");
172         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
173         
174         rect.xmax= RNA_int_get(op->ptr, "xmax");
175         rect.ymax= RNA_int_get(op->ptr, "ymax");
176         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
177         
178         for(node= snode->edittree->nodes.first; node; node= node->next) {
179                 if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
180                         if(gesture_mode==GESTURE_MODAL_SELECT)
181                                 node->flag |= SELECT;
182                         else
183                                 node->flag &= ~SELECT;
184                 }
185         }
186         
187         node_sort(snode->edittree);
188         
189         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
190
191         return OPERATOR_FINISHED;
192 }
193
194 static int node_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
195 {
196         int tweak = RNA_boolean_get(op->ptr, "tweak");
197         
198         if (tweak) {
199                 /* prevent initiating the border select if the mouse is over a node */
200                 /* this allows border select on empty space, but drag-translate on nodes */
201                 SpaceNode *snode= CTX_wm_space_node(C);
202                 ARegion *ar= CTX_wm_region(C);
203                 float mx, my;
204
205                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &mx, &my);
206                 
207                 if (node_under_mouse(snode->edittree, mx, my))
208                         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
209         }
210         
211         return WM_border_select_invoke(C, op, event);
212 }
213
214 void NODE_OT_select_border(wmOperatorType *ot)
215 {
216         /* identifiers */
217         ot->name= "Border Select";
218         ot->idname= "NODE_OT_select_border";
219         ot->description= "Use box selection to select nodes";
220         
221         /* api callbacks */
222         ot->invoke= node_border_select_invoke;
223         ot->exec= node_borderselect_exec;
224         ot->modal= WM_border_select_modal;
225         ot->cancel= WM_border_select_cancel;
226         
227         ot->poll= ED_operator_node_active;
228         
229         /* flags */
230         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
231         
232         /* rna */
233         WM_operator_properties_gesture_border(ot, FALSE);
234         RNA_def_boolean(ot->srna, "tweak", 0, "Tweak", "Only activate when mouse is not over a node - useful for tweak gesture");
235 }
236
237 /* ****** Select/Deselect All ****** */
238
239 static int node_select_all_exec(bContext *C, wmOperator *UNUSED(op))
240 {
241         SpaceNode *snode = CTX_wm_space_node(C);
242         bNode *first = snode->edittree->nodes.first;
243         bNode *node;
244         int count= 0;
245
246         for(node=first; node; node=node->next)
247                 if(node->flag & NODE_SELECT)
248                         count++;
249
250         if(count) {
251                 for(node=first; node; node=node->next)
252                         node->flag &= ~NODE_SELECT;
253         }
254         else {
255                 for(node=first; node; node=node->next)
256                         node->flag |= NODE_SELECT;
257         }
258         
259         node_sort(snode->edittree);
260         
261         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
262         return OPERATOR_FINISHED;
263 }
264
265 void NODE_OT_select_all(wmOperatorType *ot)
266 {
267         /* identifiers */
268         ot->name = "Select or Deselect All";
269         ot->description = "(De)select all nodes";
270         ot->idname = "NODE_OT_select_all";
271         
272         /* api callbacks */
273         ot->exec = node_select_all_exec;
274         ot->poll = ED_operator_node_active;
275         
276         /* flags */
277         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
278 }
279
280 /* ****** Select Linked To ****** */
281
282 static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
283 {
284         SpaceNode *snode = CTX_wm_space_node(C);
285         bNodeLink *link;
286         bNode *node;
287         
288         for (node=snode->edittree->nodes.first; node; node=node->next)
289                 node->flag &= ~NODE_TEST;
290
291         for (link=snode->edittree->links.first; link; link=link->next) {
292                 if (link->fromnode && link->tonode && (link->fromnode->flag & NODE_SELECT))
293                         link->tonode->flag |= NODE_TEST;
294         }
295         
296         for (node=snode->edittree->nodes.first; node; node=node->next) {
297                 if (node->flag & NODE_TEST)
298                         node->flag |= NODE_SELECT;
299         }
300         
301         node_sort(snode->edittree);
302         
303         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
304         return OPERATOR_FINISHED;
305 }
306
307 void NODE_OT_select_linked_to(wmOperatorType *ot)
308 {
309         /* identifiers */
310         ot->name = "Select Linked To";
311         ot->description = "Select nodes linked to the selected ones";
312         ot->idname = "NODE_OT_select_linked_to";
313         
314         /* api callbacks */
315         ot->exec = node_select_linked_to_exec;
316         ot->poll = ED_operator_node_active;
317         
318         /* flags */
319         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
320 }
321
322 /* ****** Select Linked From ****** */
323
324 static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
325 {
326         SpaceNode *snode = CTX_wm_space_node(C);
327         bNodeLink *link;
328         bNode *node;
329         
330         for(node=snode->edittree->nodes.first; node; node=node->next)
331                 node->flag &= ~NODE_TEST;
332
333         for(link=snode->edittree->links.first; link; link=link->next) {
334                 if(link->fromnode && link->tonode && (link->tonode->flag & NODE_SELECT))
335                         link->fromnode->flag |= NODE_TEST;
336         }
337         
338         for(node=snode->edittree->nodes.first; node; node=node->next) {
339                 if(node->flag & NODE_TEST)
340                         node->flag |= NODE_SELECT;
341         }
342         
343         node_sort(snode->edittree);
344         
345         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
346         return OPERATOR_FINISHED;
347 }
348
349 void NODE_OT_select_linked_from(wmOperatorType *ot)
350 {
351         /* identifiers */
352         ot->name = "Select Linked From";
353         ot->description = "Select nodes linked from the selected ones";
354         ot->idname = "NODE_OT_select_linked_from";
355         
356         /* api callbacks */
357         ot->exec = node_select_linked_from_exec;
358         ot->poll = ED_operator_node_active;
359         
360         /* flags */
361         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
362 }
363
364 /* ****** Select Same Type ****** */
365
366 static int node_select_same_type_exec(bContext *C, wmOperator *UNUSED(op))
367 {
368         SpaceNode *snode = CTX_wm_space_node(C);
369
370         node_select_same_type(snode);
371
372         node_sort(snode->edittree);
373
374         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
375         return OPERATOR_FINISHED;
376 }
377
378 void NODE_OT_select_same_type(wmOperatorType *ot)
379 {
380         /* identifiers */
381         ot->name = "Select Same Type";
382         ot->description = "Select all the same type";
383         ot->idname = "NODE_OT_select_same_type";
384         
385         /* api callbacks */
386         ot->exec = node_select_same_type_exec;
387         ot->poll = ED_operator_node_active;
388         
389         /* flags */
390         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
391 }
392
393 /* ****** Select The Next/Prev Node Of The Same Type ****** */
394
395 static int node_select_same_type_next_exec(bContext *C, wmOperator *UNUSED(op))
396 {
397         SpaceNode *snode = CTX_wm_space_node(C);
398
399         node_select_same_type_np(snode, 0);
400
401         node_sort(snode->edittree);
402
403         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
404
405         return OPERATOR_FINISHED;
406 }
407
408 void NODE_OT_select_same_type_next(wmOperatorType *ot)
409 {
410         /* identifiers */
411         ot->name = "Select Same Type Next";
412         ot->description = "Select the next node of the same type.";
413         ot->idname = "NODE_OT_select_same_type_next";
414         
415         /* api callbacks */
416         ot->exec = node_select_same_type_next_exec;
417         ot->poll = ED_operator_node_active;
418         
419         /* flags */
420         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
421 }
422
423 static int node_select_same_type_prev_exec(bContext *C, wmOperator *UNUSED(op))
424 {
425         SpaceNode *snode = CTX_wm_space_node(C);
426
427         node_select_same_type_np(snode, 1);
428
429         node_sort(snode->edittree);
430
431         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
432         return OPERATOR_FINISHED;
433 }
434
435 void NODE_OT_select_same_type_prev(wmOperatorType *ot)
436 {
437         /* identifiers */
438         ot->name = "Select Same Type Prev";
439         ot->description = "Select the prev node of the same type.";
440         ot->idname = "NODE_OT_select_same_type_prev";
441         
442         /* api callbacks */
443         ot->exec = node_select_same_type_prev_exec;
444         ot->poll = ED_operator_node_active;
445         
446         /* flags */
447         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
448 }