Blender  V2.59
node_select.c
Go to the documentation of this file.
00001 /*
00002  * $Id: node_select.c 37246 2011-06-06 11:04:54Z nazgul $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * 
00024  * Contributor(s): Blender Foundation, Nathan Letwory
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <stdio.h>
00035 
00036 #include "DNA_node_types.h"
00037 #include "DNA_scene_types.h"
00038 
00039 #include "BKE_context.h"
00040 
00041 #include "BLI_rect.h"
00042 #include "BLI_utildefines.h"
00043 
00044 #include "ED_screen.h"
00045 #include "ED_types.h"
00046 
00047 #include "RNA_access.h"
00048 #include "RNA_define.h"
00049 
00050 #include "WM_api.h"
00051 #include "WM_types.h"
00052 
00053 #include "UI_view2d.h"
00054  
00055 #include "node_intern.h"
00056 
00057 /* ****** helpers ****** */
00058 
00059 static bNode *node_under_mouse(bNodeTree *ntree, int mx, int my)
00060 {
00061         bNode *node;
00062         
00063         for(next_node(ntree); (node=next_node(NULL));) {
00064                 /* node body (header and scale are in other operators) */
00065                 if (BLI_in_rctf(&node->totr, mx, my))
00066                         return node;
00067         }
00068         return NULL;
00069 }
00070 
00071 /* ****** Click Select ****** */
00072  
00073 static bNode *node_mouse_select(SpaceNode *snode, ARegion *ar, const int mval[2], short extend)
00074 {
00075         bNode *node;
00076         float mx, my;
00077         
00078         /* get mouse coordinates in view2d space */
00079         mx= (float)mval[0];
00080         my= (float)mval[1];
00081         
00082         UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my);
00083         
00084         /* find the closest visible node */
00085         node = node_under_mouse(snode->edittree, mx, my);
00086         
00087         if (node) {
00088                 if (extend == 0) {
00089                         node_deselectall(snode);
00090                         node->flag |= SELECT;
00091                 }
00092                 else
00093                         node->flag ^= SELECT;
00094                         
00095                 node_set_active(snode, node);
00096         }
00097 
00098         return node;
00099 }
00100 
00101 static int node_select_exec(bContext *C, wmOperator *op)
00102 {
00103         SpaceNode *snode= CTX_wm_space_node(C);
00104         ARegion *ar= CTX_wm_region(C);
00105         int mval[2];
00106         short extend;
00107         bNode *node= NULL;
00108         
00109         /* get settings from RNA properties for operator */
00110         mval[0] = RNA_int_get(op->ptr, "mouse_x");
00111         mval[1] = RNA_int_get(op->ptr, "mouse_y");
00112         
00113         extend = RNA_boolean_get(op->ptr, "extend");
00114         
00115         /* perform the select */
00116         node= node_mouse_select(snode, ar, mval, extend);
00117         
00118         /* send notifiers */
00119         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00120         
00121         /* allow tweak event to work too */
00122         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
00123 }
00124 
00125 static int node_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
00126 {
00127         RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
00128         RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
00129 
00130         return node_select_exec(C,op);
00131 }
00132 
00133 
00134 void NODE_OT_select(wmOperatorType *ot)
00135 {
00136         /* identifiers */
00137         ot->name= "Select";
00138         ot->idname= "NODE_OT_select";
00139         ot->description= "Select node under cursor";
00140         
00141         /* api callbacks */
00142         ot->invoke= node_select_invoke;
00143         ot->poll= ED_operator_node_active;
00144         
00145         /* flags */
00146         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00147         
00148         /* properties */
00149         RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
00150         RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
00151         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
00152 }
00153 
00154 /* ****** Border Select ****** */
00155 
00156 static int node_borderselect_exec(bContext *C, wmOperator *op)
00157 {
00158         SpaceNode *snode= CTX_wm_space_node(C);
00159         ARegion *ar= CTX_wm_region(C);
00160         bNode *node;
00161         rcti rect;
00162         rctf rectf;
00163         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
00164         
00165         rect.xmin= RNA_int_get(op->ptr, "xmin");
00166         rect.ymin= RNA_int_get(op->ptr, "ymin");
00167         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
00168         
00169         rect.xmax= RNA_int_get(op->ptr, "xmax");
00170         rect.ymax= RNA_int_get(op->ptr, "ymax");
00171         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
00172         
00173         for(node= snode->edittree->nodes.first; node; node= node->next) {
00174                 if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
00175                         if(gesture_mode==GESTURE_MODAL_SELECT)
00176                                 node->flag |= SELECT;
00177                         else
00178                                 node->flag &= ~SELECT;
00179                 }
00180         }
00181         
00182         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00183 
00184         return OPERATOR_FINISHED;
00185 }
00186 
00187 static int node_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
00188 {
00189         int tweak = RNA_boolean_get(op->ptr, "tweak");
00190         
00191         if (tweak) {
00192                 /* prevent initiating the border select if the mouse is over a node */
00193                 /* this allows border select on empty space, but drag-translate on nodes */
00194                 SpaceNode *snode= CTX_wm_space_node(C);
00195                 ARegion *ar= CTX_wm_region(C);
00196                 float mx, my;
00197 
00198                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &mx, &my);
00199                 
00200                 if (node_under_mouse(snode->edittree, mx, my))
00201                         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
00202         }
00203         
00204         return WM_border_select_invoke(C, op, event);
00205 }
00206 
00207 void NODE_OT_select_border(wmOperatorType *ot)
00208 {
00209         /* identifiers */
00210         ot->name= "Border Select";
00211         ot->idname= "NODE_OT_select_border";
00212         ot->description= "Use box selection to select nodes";
00213         
00214         /* api callbacks */
00215         ot->invoke= node_border_select_invoke;
00216         ot->exec= node_borderselect_exec;
00217         ot->modal= WM_border_select_modal;
00218         ot->cancel= WM_border_select_cancel;
00219         
00220         ot->poll= ED_operator_node_active;
00221         
00222         /* flags */
00223         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00224         
00225         /* rna */
00226         WM_operator_properties_gesture_border(ot, FALSE);
00227         RNA_def_boolean(ot->srna, "tweak", 0, "Tweak", "Only activate when mouse is not over a node - useful for tweak gesture");
00228 }
00229 
00230 /* ****** Select/Deselect All ****** */
00231 
00232 static int node_select_all_exec(bContext *C, wmOperator *UNUSED(op))
00233 {
00234         SpaceNode *snode = CTX_wm_space_node(C);
00235         bNode *first = snode->edittree->nodes.first;
00236         bNode *node;
00237         int count= 0;
00238 
00239         for(node=first; node; node=node->next)
00240                 if(node->flag & NODE_SELECT)
00241                         count++;
00242 
00243         if(count) {
00244                 for(node=first; node; node=node->next)
00245                         node->flag &= ~NODE_SELECT;
00246         }
00247         else {
00248                 for(node=first; node; node=node->next)
00249                         node->flag |= NODE_SELECT;
00250         }
00251         
00252         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00253         return OPERATOR_FINISHED;
00254 }
00255 
00256 void NODE_OT_select_all(wmOperatorType *ot)
00257 {
00258         /* identifiers */
00259         ot->name = "Select or Deselect All";
00260         ot->description = "(De)select all nodes";
00261         ot->idname = "NODE_OT_select_all";
00262         
00263         /* api callbacks */
00264         ot->exec = node_select_all_exec;
00265         ot->poll = ED_operator_node_active;
00266         
00267         /* flags */
00268         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00269 }
00270 
00271 /* ****** Select Linked To ****** */
00272 
00273 static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
00274 {
00275         SpaceNode *snode = CTX_wm_space_node(C);
00276         bNodeLink *link;
00277         bNode *node;
00278         
00279         for (node=snode->edittree->nodes.first; node; node=node->next)
00280                 node->flag &= ~NODE_TEST;
00281 
00282         for (link=snode->edittree->links.first; link; link=link->next) {
00283                 if (link->fromnode && link->tonode && (link->fromnode->flag & NODE_SELECT))
00284                         link->tonode->flag |= NODE_TEST;
00285         }
00286         
00287         for (node=snode->edittree->nodes.first; node; node=node->next) {
00288                 if (node->flag & NODE_TEST)
00289                         node->flag |= NODE_SELECT;
00290         }
00291         
00292         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00293         return OPERATOR_FINISHED;
00294 }
00295 
00296 void NODE_OT_select_linked_to(wmOperatorType *ot)
00297 {
00298         /* identifiers */
00299         ot->name = "Select Linked To";
00300         ot->description = "Select nodes linked to the selected ones";
00301         ot->idname = "NODE_OT_select_linked_to";
00302         
00303         /* api callbacks */
00304         ot->exec = node_select_linked_to_exec;
00305         ot->poll = ED_operator_node_active;
00306         
00307         /* flags */
00308         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00309 }
00310 
00311 /* ****** Select Linked From ****** */
00312 
00313 static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
00314 {
00315         SpaceNode *snode = CTX_wm_space_node(C);
00316         bNodeLink *link;
00317         bNode *node;
00318         
00319         for(node=snode->edittree->nodes.first; node; node=node->next)
00320                 node->flag &= ~NODE_TEST;
00321 
00322         for(link=snode->edittree->links.first; link; link=link->next) {
00323                 if(link->fromnode && link->tonode && (link->tonode->flag & NODE_SELECT))
00324                         link->fromnode->flag |= NODE_TEST;
00325         }
00326         
00327         for(node=snode->edittree->nodes.first; node; node=node->next) {
00328                 if(node->flag & NODE_TEST)
00329                         node->flag |= NODE_SELECT;
00330         }
00331         
00332         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00333         return OPERATOR_FINISHED;
00334 }
00335 
00336 void NODE_OT_select_linked_from(wmOperatorType *ot)
00337 {
00338         /* identifiers */
00339         ot->name = "Select Linked From";
00340         ot->description = "Select nodes linked from the selected ones";
00341         ot->idname = "NODE_OT_select_linked_from";
00342         
00343         /* api callbacks */
00344         ot->exec = node_select_linked_from_exec;
00345         ot->poll = ED_operator_node_active;
00346         
00347         /* flags */
00348         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00349 }
00350 
00351 /* ****** Select Same Type ****** */
00352 
00353 static int node_select_same_type_exec(bContext *C, wmOperator *UNUSED(op))
00354 {
00355         SpaceNode *snode = CTX_wm_space_node(C);
00356 
00357         node_select_same_type(snode);
00358         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00359         return OPERATOR_FINISHED;
00360 }
00361 
00362 void NODE_OT_select_same_type(wmOperatorType *ot)
00363 {
00364         /* identifiers */
00365         ot->name = "Select Same Type";
00366         ot->description = "Select all the same type";
00367         ot->idname = "NODE_OT_select_same_type";
00368         
00369         /* api callbacks */
00370         ot->exec = node_select_same_type_exec;
00371         ot->poll = ED_operator_node_active;
00372         
00373         /* flags */
00374         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00375 }
00376 
00377 /* ****** Select The Next/Prev Node Of The Same Type ****** */
00378 
00379 static int node_select_same_type_next_exec(bContext *C, wmOperator *UNUSED(op))
00380 {
00381         SpaceNode *snode = CTX_wm_space_node(C);
00382 
00383         node_select_same_type_np(snode, 0);
00384         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00385         return OPERATOR_FINISHED;
00386 }
00387 
00388 void NODE_OT_select_same_type_next(wmOperatorType *ot)
00389 {
00390         /* identifiers */
00391         ot->name = "Select Same Type Next";
00392         ot->description = "Select the next node of the same type.";
00393         ot->idname = "NODE_OT_select_same_type_next";
00394         
00395         /* api callbacks */
00396         ot->exec = node_select_same_type_next_exec;
00397         ot->poll = ED_operator_node_active;
00398         
00399         /* flags */
00400         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00401 }
00402 
00403 static int node_select_same_type_prev_exec(bContext *C, wmOperator *UNUSED(op))
00404 {
00405         SpaceNode *snode = CTX_wm_space_node(C);
00406 
00407         node_select_same_type_np(snode, 1);
00408         WM_event_add_notifier(C, NC_NODE|NA_SELECTED, NULL);
00409         return OPERATOR_FINISHED;
00410 }
00411 
00412 void NODE_OT_select_same_type_prev(wmOperatorType *ot)
00413 {
00414         /* identifiers */
00415         ot->name = "Select Same Type Prev";
00416         ot->description = "Select the prev node of the same type.";
00417         ot->idname = "NODE_OT_select_same_type_prev";
00418         
00419         /* api callbacks */
00420         ot->exec = node_select_same_type_prev_exec;
00421         ot->poll = ED_operator_node_active;
00422         
00423         /* flags */
00424         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
00425 }