e82917feb2122b363c42482d09620078e53666e6
[blender.git] / source / blender / editors / space_node / node_header.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
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_node/node_header.c
28  *  \ingroup spnode
29  */
30
31 #include <string.h>
32
33 #include "DNA_space_types.h"
34 #include "DNA_node_types.h"
35 #include "DNA_screen_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_blenlib.h"
40 #include "BLI_utildefines.h"
41
42 #include "BLF_translation.h"
43
44 #include "BKE_blender.h"
45 #include "BKE_context.h"
46 #include "BKE_global.h"
47 #include "BKE_main.h"
48 #include "BKE_node.h"
49 #include "BKE_scene.h"
50 #include "BKE_screen.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "UI_view2d.h"
56
57 #include "node_intern.h"  /* own include */
58
59 /* ************************ add menu *********************** */
60
61 static void do_node_add(bContext *C, bNodeTemplate *ntemp)
62 {
63         Main *bmain = CTX_data_main(C);
64         Scene *scene = CTX_data_scene(C);
65         SpaceNode *snode = CTX_wm_space_node(C);
66         ScrArea *sa = CTX_wm_area(C);
67         ARegion *ar;
68         bNode *node, *node_new;
69         
70         /* get location to add node at mouse */
71         for (ar = sa->regionbase.first; ar; ar = ar->next) {
72                 if (ar->regiontype == RGN_TYPE_WINDOW) {
73                         wmWindow *win = CTX_wm_window(C);
74                         int x = win->eventstate->x - ar->winrct.xmin;
75                         int y = win->eventstate->y - ar->winrct.ymin;
76                         
77                         if (y < 60) y += 60;
78                         UI_view2d_region_to_view(&ar->v2d, x, y, &snode->cursor[0], &snode->cursor[1]);
79                 }
80         }
81         
82         /* store selection in temp test flag */
83         for (node = snode->edittree->nodes.first; node; node = node->next) {
84                 if (node->flag & NODE_SELECT) node->flag |= NODE_TEST;
85                 else node->flag &= ~NODE_TEST;
86         }
87         
88         node_new = node_add_node(snode, bmain, scene, ntemp, snode->cursor[0], snode->cursor[1]);
89         
90         /* select previous selection before autoconnect */
91         for (node = snode->edittree->nodes.first; node; node = node->next) {
92                 if (node->flag & NODE_TEST) node->flag |= NODE_SELECT;
93         }
94         
95         /* deselect after autoconnection */
96         for (node = snode->edittree->nodes.first; node; node = node->next) {
97                 if (node->flag & NODE_TEST) node->flag &= ~NODE_SELECT;
98         }
99
100         /* once this is called from an operator, this should be removed */
101         if (node_new) {
102                 char undostr[BKE_UNDO_STR_MAX];
103                 BLI_snprintf(undostr, sizeof(undostr), "Add Node %s", nodeLabel(node_new));
104                 BKE_write_undo(C, undostr);
105         }
106
107         snode_notify(C, snode);
108         snode_dag_update(C, snode);
109 }
110
111 static void do_node_add_static(bContext *C, void *UNUSED(arg), int event)
112 {
113         Main *bmain = CTX_data_main(C);
114         Scene *scene = CTX_data_scene(C);
115         bNodeTemplate ntemp;
116         
117         ntemp.type = event;
118         ntemp.main = bmain;
119         ntemp.scene = scene;
120         
121         do_node_add(C, &ntemp);
122 }
123
124 static void do_node_add_group(bContext *C, void *UNUSED(arg), int event)
125 {
126         SpaceNode *snode = CTX_wm_space_node(C);
127         Main *bmain = CTX_data_main(C);
128         Scene *scene = CTX_data_scene(C);
129         bNodeTemplate ntemp;
130         
131         if (event >= 0) {
132                 ntemp.ngroup = BLI_findlink(&G.main->nodetree, event);
133                 ntemp.type = ntemp.ngroup->nodetype;
134         }
135         else {
136                 ntemp.type = -event;
137                 switch (ntemp.type) {
138                         case NODE_GROUP:
139                                 ntemp.ngroup = ntreeAddTree("Group", snode->treetype, ntemp.type);
140                                 break;
141                         default:
142                                 ntemp.ngroup = NULL;
143                 }
144         }
145         if (!ntemp.ngroup)
146                 return;
147         
148         ntemp.main = bmain;
149         ntemp.scene = scene;
150         
151         do_node_add(C, &ntemp);
152 }
153
154 static int node_tree_has_type(int treetype, int nodetype)
155 {
156         bNodeTreeType *ttype = ntreeGetType(treetype);
157         bNodeType *ntype;
158         for (ntype = ttype->node_types.first; ntype; ntype = ntype->next) {
159                 if (ntype->type == nodetype)
160                         return 1;
161         }
162         return 0;
163 }
164
165 static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass)
166 {
167         Main *bmain = CTX_data_main(C);
168         Scene *scene = CTX_data_scene(C);
169         SpaceNode *snode = CTX_wm_space_node(C);
170         bNodeTree *ntree;
171         int nodeclass = GET_INT_FROM_POINTER(arg_nodeclass);
172         int event, compatibility = 0;
173         
174         ntree = snode->nodetree;
175         
176         if (!ntree) {
177                 uiItemS(layout);
178                 return;
179         }
180
181         if (ntree->type == NTREE_SHADER) {
182                 if (BKE_scene_use_new_shading_nodes(scene))
183                         compatibility = NODE_NEW_SHADING;
184                 else
185                         compatibility = NODE_OLD_SHADING;
186         }
187         
188         if (nodeclass == NODE_CLASS_GROUP) {
189                 bNodeTree *ngroup;
190                 
191                 uiLayoutSetFunc(layout, do_node_add_group, NULL);
192                 
193                 /* XXX hack: negative numbers used for empty group types */
194                 if (node_tree_has_type(ntree->type, NODE_GROUP))
195                         uiItemV(layout, IFACE_("New Group"), 0, -NODE_GROUP);
196                 uiItemS(layout);
197                 
198                 for (ngroup = bmain->nodetree.first, event = 0; ngroup; ngroup = ngroup->id.next, ++event) {
199                         /* only use group trees */
200                         if (ngroup->type == ntree->type && ngroup->nodetype == NODE_GROUP) {
201                                 uiItemV(layout, ngroup->id.name + 2, 0, event);
202                         }
203                 }
204         }
205         else {
206                 bNodeType *ntype;
207                 
208                 uiLayoutSetFunc(layout, do_node_add_static, NULL);
209                 
210                 for (ntype = ntreeGetType(ntree->type)->node_types.first; ntype; ntype = ntype->next) {
211                         if (ntype->nclass == nodeclass && ntype->name) {
212                                 if (!compatibility || (ntype->compatibility & compatibility)) {
213                                         uiItemV(layout, IFACE_(ntype->name), 0, ntype->type);
214                                 }
215                         }
216                 }
217         }
218 }
219
220 static void node_menu_add_foreach_cb(void *calldata, int nclass, const char *name)
221 {
222         uiLayout *layout = calldata;
223         uiItemMenuF(layout, IFACE_(name), 0, node_add_menu, SET_INT_IN_POINTER(nclass));
224 }
225
226 static void node_menu_add(const bContext *C, Menu *menu)
227 {
228         Scene *scene = CTX_data_scene(C);
229         SpaceNode *snode = CTX_wm_space_node(C);
230         uiLayout *layout = menu->layout;
231         bNodeTreeType *ntreetype = ntreeGetType(snode->treetype);
232
233         if (!snode->nodetree)
234                 uiLayoutSetActive(layout, FALSE);
235         
236         uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
237         uiItemO(layout, "Search ...", 0, "NODE_OT_add_search");
238         
239         if (ntreetype && ntreetype->foreach_nodeclass)
240                 ntreetype->foreach_nodeclass(scene, layout, node_menu_add_foreach_cb);
241 }
242
243 void node_menus_register(void)
244 {
245         MenuType *mt;
246
247         mt = MEM_callocN(sizeof(MenuType), "spacetype node menu add");
248         strcpy(mt->idname, "NODE_MT_add");
249         strcpy(mt->label, "Add");
250         mt->draw = node_menu_add;
251         WM_menutype_add(mt);
252 }