68f5dd6bf1492b2afb859f8bf92c6085290df6a3
[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
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "DNA_space_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_utildefines.h"
44
45 #include "BLF_translation.h"
46
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_screen.h"
50 #include "BKE_node.h"
51 #include "BKE_main.h"
52
53 #include "RNA_access.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58 #include "UI_interface.h"
59 #include "UI_interface_icons.h"
60 #include "UI_resources.h"
61 #include "UI_view2d.h"
62
63 #include "node_intern.h"
64
65 /* ************************ add menu *********************** */
66
67 static void do_node_add(bContext *C, bNodeTemplate *ntemp)
68 {
69         Main *bmain= CTX_data_main(C);
70         Scene *scene= CTX_data_scene(C);
71         SpaceNode *snode= CTX_wm_space_node(C);
72         ScrArea *sa= CTX_wm_area(C);
73         ARegion *ar;
74         bNode *node;
75         
76         /* get location to add node at mouse */
77         for(ar=sa->regionbase.first; ar; ar=ar->next) {
78                 if(ar->regiontype == RGN_TYPE_WINDOW) {
79                         wmWindow *win= CTX_wm_window(C);
80                         int x= win->eventstate->x - ar->winrct.xmin;
81                         int y= win->eventstate->y - ar->winrct.ymin;
82                         
83                         if(y < 60) y+= 60;
84                         UI_view2d_region_to_view(&ar->v2d, x, y, &snode->mx, &snode->my);
85                 }
86         }
87         
88         /* store selection in temp test flag */
89         for(node= snode->edittree->nodes.first; node; node= node->next) {
90                 if(node->flag & NODE_SELECT) node->flag |= NODE_TEST;
91                 else node->flag &= ~NODE_TEST;
92         }
93         
94         /* node= */ node_add_node(snode, bmain, scene, ntemp, snode->mx, snode->my);
95         
96         /* select previous selection before autoconnect */
97         for(node= snode->edittree->nodes.first; node; node= node->next) {
98                 if(node->flag & NODE_TEST) node->flag |= NODE_SELECT;
99         }
100         
101         /* deselect after autoconnection */
102         for(node= snode->edittree->nodes.first; node; node= node->next) {
103                 if(node->flag & NODE_TEST) node->flag &= ~NODE_SELECT;
104         }
105                 
106         snode_notify(C, snode);
107         snode_dag_update(C, snode);
108 }
109
110 static void do_node_add_static(bContext *C, void *UNUSED(arg), int event)
111 {
112         bNodeTemplate ntemp;
113         ntemp.type = event;
114         do_node_add(C, &ntemp);
115 }
116
117 static void do_node_add_group(bContext *C, void *UNUSED(arg), int event)
118 {
119         SpaceNode *snode= CTX_wm_space_node(C);
120         bNodeTemplate ntemp;
121         
122         if (event>=0) {
123                 ntemp.ngroup= BLI_findlink(&G.main->nodetree, event);
124                 ntemp.type = ntemp.ngroup->nodetype;
125         }
126         else {
127                 ntemp.type = -event;
128                 switch (ntemp.type) {
129                 case NODE_GROUP:
130                         ntemp.ngroup = ntreeAddTree("Group", snode->treetype, ntemp.type);
131                         break;
132                 case NODE_FORLOOP:
133                         ntemp.ngroup = ntreeAddTree("For Loop", snode->treetype, ntemp.type);
134                         break;
135                 case NODE_WHILELOOP:
136                         ntemp.ngroup = ntreeAddTree("While Loop", snode->treetype, ntemp.type);
137                         break;
138                 default:
139                         ntemp.ngroup = NULL;
140                 }
141         }
142         if (!ntemp.ngroup)
143                 return;
144         
145         do_node_add(C, &ntemp);
146 }
147
148 #if 0 /* disabled */
149 static void do_node_add_dynamic(bContext *C, void *UNUSED(arg), int event)
150 {
151         bNodeTemplate ntemp;
152         ntemp.type = NODE_DYNAMIC;
153         do_node_add(C, &ntemp);
154 }
155 #endif
156
157 static int node_tree_has_type(int treetype, int nodetype)
158 {
159         bNodeTreeType *ttype= ntreeGetType(treetype);
160         bNodeType *ntype;
161         for (ntype=ttype->node_types.first; ntype; ntype=ntype->next) {
162                 if (ntype->type==nodetype)
163                         return 1;
164         }
165         return 0;
166 }
167
168 static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass)
169 {
170         Main *bmain= CTX_data_main(C);
171         SpaceNode *snode= CTX_wm_space_node(C);
172         bNodeTree *ntree;
173         int nodeclass= GET_INT_FROM_POINTER(arg_nodeclass);
174         int event;
175         
176         ntree = snode->nodetree;
177         
178         if(!ntree) {
179                 uiItemS(layout);
180                 return;
181         }
182         
183         if (nodeclass==NODE_CLASS_GROUP) {
184                 bNodeTree *ngroup;
185                 
186                 uiLayoutSetFunc(layout, do_node_add_group, NULL);
187                 
188                 /* XXX hack: negative numbers used for empty group types */
189                 if (node_tree_has_type(ntree->type, NODE_GROUP))
190                         uiItemV(layout, "New Group", 0, -NODE_GROUP);
191                 if (node_tree_has_type(ntree->type, NODE_FORLOOP))
192                         uiItemV(layout, "New For Loop", 0, -NODE_FORLOOP);
193                 if (node_tree_has_type(ntree->type, NODE_WHILELOOP))
194                         uiItemV(layout, "New While Loop", 0, -NODE_WHILELOOP);
195                 uiItemS(layout);
196                 
197                 for(ngroup=bmain->nodetree.first, event=0; ngroup; ngroup= ngroup->id.next, ++event) {
198                         /* only use group trees */
199                         if (ngroup->type==ntree->type && ELEM3(ngroup->nodetype, NODE_GROUP, NODE_FORLOOP, NODE_WHILELOOP)) {
200                                 uiItemV(layout, ngroup->id.name+2, 0, event);
201                         }
202                 }
203         }
204         else if (nodeclass==NODE_DYNAMIC) {
205                 /* disabled */
206         }
207         else {
208                 bNodeType *ntype;
209                 
210                 uiLayoutSetFunc(layout, do_node_add_static, NULL);
211                 
212                 for (ntype=ntreeGetType(ntree->type)->node_types.first; ntype; ntype=ntype->next) {
213                         if(ntype->nclass==nodeclass && ntype->name)
214                                 uiItemV(layout, ntype->name, 0, ntype->type);
215                 }
216         }
217 }
218
219 static void node_menu_add(const bContext *C, Menu *menu)
220 {
221         SpaceNode *snode= CTX_wm_space_node(C);
222         uiLayout *layout= menu->layout;
223
224         if(!snode->nodetree)
225                 uiLayoutSetActive(layout, 0);
226
227         if(snode->treetype==NTREE_SHADER) {
228                 uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
229                 uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
230                 uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
231                 uiItemMenuF(layout, IFACE_("Vector"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR));
232                 uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
233                 uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
234                 uiItemMenuF(layout, IFACE_("Dynamic"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_DYNAMIC));
235                 uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
236         }
237         else if(snode->treetype==NTREE_COMPOSIT) {
238                 uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
239                 uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
240                 uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
241                 uiItemMenuF(layout, IFACE_("Vector"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_VECTOR));
242                 uiItemMenuF(layout, IFACE_("Filter"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_FILTER));
243                 uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
244                 uiItemMenuF(layout, IFACE_("Matte"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_MATTE));
245                 uiItemMenuF(layout, IFACE_("Distort"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT));
246                 uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
247                 uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
248         }
249         else if(snode->treetype==NTREE_TEXTURE) {
250                 uiItemMenuF(layout, IFACE_("Input"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_INPUT));
251                 uiItemMenuF(layout, IFACE_("Output"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OUTPUT));
252                 uiItemMenuF(layout, IFACE_("Color"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_OP_COLOR));
253                 uiItemMenuF(layout, IFACE_("Patterns"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_PATTERN));
254                 uiItemMenuF(layout, IFACE_("Textures"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_TEXTURE));
255                 uiItemMenuF(layout, IFACE_("Convertor"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_CONVERTOR));
256                 uiItemMenuF(layout, IFACE_("Distort"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_DISTORT));
257                 uiItemMenuF(layout, IFACE_("Group"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_GROUP));
258                 uiItemMenuF(layout, IFACE_("Layout"), 0, node_add_menu, SET_INT_IN_POINTER(NODE_CLASS_LAYOUT));
259         }
260 }
261
262 void node_menus_register(void)
263 {
264         MenuType *mt;
265
266         mt= MEM_callocN(sizeof(MenuType), "spacetype node menu add");
267         strcpy(mt->idname, "NODE_MT_add");
268         strcpy(mt->label, "Add");
269         mt->draw= node_menu_add;
270         WM_menutype_add(mt);
271 }
272