code cleanup: lazy init enum for node search
[blender.git] / source / blender / editors / space_node / node_add.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) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Nathan Letwory
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_node/node_relationships.c
29  *  \ingroup spnode
30  */
31
32 #include <errno.h>
33
34 #include "DNA_node_types.h"
35
36 #include "BLI_math.h"
37
38 #include "BKE_context.h"
39 #include "BKE_image.h"
40 #include "BKE_library.h"
41 #include "BKE_main.h"
42 #include "BKE_node.h"
43 #include "BKE_report.h"
44
45 #include "ED_node.h"  /* own include */
46 #include "ED_screen.h"
47 #include "ED_render.h"
48
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51 #include "RNA_enum_types.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "UI_view2d.h"
57
58 #include "node_intern.h"  /* own include */
59
60 /* can be called from menus too, but they should do own undopush and redraws */
61 bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene,
62                      bNodeTemplate *ntemp, float locx, float locy)
63 {
64         bNode *node = NULL, *gnode;
65
66         node_deselect_all(snode);
67
68         node = nodeAddNode(snode->edittree, ntemp);
69
70         /* generics */
71         if (node) {
72                 node_select(node);
73
74                 gnode = node_tree_get_editgroup(snode->nodetree);
75                 // arbitrary y offset of 60 so its visible
76                 if (gnode) {
77                         nodeFromView(gnode, locx, locy + 60.0f, &node->locx, &node->locy);
78                 }
79                 else {
80                         node->locx = locx;
81                         node->locy = locy + 60.0f;
82                 }
83
84                 ntreeUpdateTree(snode->edittree);
85                 ED_node_set_active(bmain, snode->edittree, node);
86
87                 if (snode->nodetree->type == NTREE_COMPOSIT) {
88                         if (ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE)) {
89                                 node->id = &scene->id;
90                         }
91                         else if (ELEM3(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_MOVIEDISTORTION, CMP_NODE_STABILIZE2D)) {
92                                 node->id = (ID *)scene->clip;
93                         }
94
95                         ntreeCompositForceHidden(snode->edittree, scene);
96                 }
97
98                 if (node->id)
99                         id_us_plus(node->id);
100
101
102                 if (snode->flag & SNODE_USE_HIDDEN_PREVIEW)
103                         node->flag &= ~NODE_PREVIEW;
104
105                 snode_update(snode, node);
106         }
107
108         if (snode->nodetree->type == NTREE_TEXTURE) {
109                 ntreeTexCheckCyclics(snode->edittree);
110         }
111
112         return node;
113 }
114
115 /* ********************** Add reroute operator ***************** */
116 static int add_reroute_intersect_check(bNodeLink *link, float mcoords[][2], int tot, float result[2])
117 {
118         float coord_array[NODE_LINK_RESOL + 1][2];
119         int i, b;
120
121         if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
122
123                 for (i = 0; i < tot - 1; i++)
124                         for (b = 0; b < NODE_LINK_RESOL; b++)
125                                 if (isect_line_line_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
126                                         result[0] = (mcoords[i][0] + mcoords[i + 1][0]) / 2.0f;
127                                         result[1] = (mcoords[i][1] + mcoords[i + 1][1]) / 2.0f;
128                                         return 1;
129                                 }
130         }
131         return 0;
132 }
133
134 static int add_reroute_exec(bContext *C, wmOperator *op)
135 {
136         SpaceNode *snode = CTX_wm_space_node(C);
137         ARegion *ar = CTX_wm_region(C);
138         bNode *gnode = node_tree_get_editgroup(snode->nodetree);
139         float mcoords[256][2];
140         int i = 0;
141
142         RNA_BEGIN(op->ptr, itemptr, "path")
143         {
144                 float loc[2];
145
146                 RNA_float_get_array(&itemptr, "loc", loc);
147                 UI_view2d_region_to_view(&ar->v2d, (short)loc[0], (short)loc[1],
148                                          &mcoords[i][0], &mcoords[i][1]);
149                 i++;
150                 if (i >= 256) break;
151         }
152         RNA_END;
153
154         if (i > 1) {
155                 bNodeLink *link;
156                 float insertPoint[2];
157
158                 for (link = snode->edittree->links.first; link; link = link->next) {
159                         if (add_reroute_intersect_check(link, mcoords, i, insertPoint)) {
160                                 bNodeTemplate ntemp;
161                                 bNode *rerouteNode;
162
163                                 /* always first */
164                                 ED_preview_kill_jobs(C);
165
166                                 node_deselect_all(snode);
167
168                                 ntemp.type = NODE_REROUTE;
169                                 rerouteNode = nodeAddNode(snode->edittree, &ntemp);
170                                 if (gnode) {
171                                         nodeFromView(gnode, insertPoint[0], insertPoint[1], &rerouteNode->locx, &rerouteNode->locy);
172                                 }
173                                 else {
174                                         rerouteNode->locx = insertPoint[0];
175                                         rerouteNode->locy = insertPoint[1];
176                                 }
177
178                                 nodeAddLink(snode->edittree, link->fromnode, link->fromsock, rerouteNode, rerouteNode->inputs.first);
179                                 link->fromnode = rerouteNode;
180                                 link->fromsock = rerouteNode->outputs.first;
181
182                                 /* always last */
183                                 ntreeUpdateTree(snode->edittree);
184                                 snode_notify(C, snode);
185                                 snode_dag_update(C, snode);
186
187                                 return OPERATOR_FINISHED; // add one reroute at the time.
188                         }
189                 }
190
191                 return OPERATOR_CANCELLED;
192
193         }
194
195         return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
196 }
197
198 void NODE_OT_add_reroute(wmOperatorType *ot)
199 {
200         PropertyRNA *prop;
201
202         ot->name = "Add reroute";
203         ot->idname = "NODE_OT_add_reroute";
204
205         ot->invoke = WM_gesture_lines_invoke;
206         ot->modal = WM_gesture_lines_modal;
207         ot->exec = add_reroute_exec;
208         ot->cancel = WM_gesture_lines_cancel;
209
210         ot->poll = ED_operator_node_active;
211
212         /* flags */
213         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
214
215         prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
216         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
217         /* internal */
218         RNA_def_int(ot->srna, "cursor", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
219 }
220
221
222 /* ****************** Add File Node Operator  ******************* */
223
224 static int node_add_file_exec(bContext *C, wmOperator *op)
225 {
226         Main *bmain = CTX_data_main(C);
227         Scene *scene = CTX_data_scene(C);
228         SpaceNode *snode = CTX_wm_space_node(C);
229         bNode *node;
230         Image *ima = NULL;
231         bNodeTemplate ntemp;
232
233         /* check input variables */
234         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
235                 char path[FILE_MAX];
236                 RNA_string_get(op->ptr, "filepath", path);
237
238                 errno = 0;
239
240                 ima = BKE_image_load_exists(path);
241
242                 if (!ima) {
243                         BKE_reportf(op->reports, RPT_ERROR, "Can't read image: \"%s\", %s", path, errno ? strerror(errno) : "Unsupported format");
244                         return OPERATOR_CANCELLED;
245                 }
246         }
247         else if (RNA_struct_property_is_set(op->ptr, "name")) {
248                 char name[MAX_ID_NAME - 2];
249                 RNA_string_get(op->ptr, "name", name);
250                 ima = (Image *)BKE_libblock_find_name(ID_IM, name);
251
252                 if (!ima) {
253                         BKE_reportf(op->reports, RPT_ERROR, "Image named \"%s\", not found", name);
254                         return OPERATOR_CANCELLED;
255                 }
256         }
257
258         node_deselect_all(snode);
259
260         switch (snode->nodetree->type) {
261                 case NTREE_SHADER:
262                         ntemp.type = SH_NODE_TEX_IMAGE;
263                         break;
264                 case NTREE_TEXTURE:
265                         ntemp.type = TEX_NODE_IMAGE;
266                         break;
267                 case NTREE_COMPOSIT:
268                         ntemp.type = CMP_NODE_IMAGE;
269                         break;
270                 default:
271                         return OPERATOR_CANCELLED;
272         }
273
274         ED_preview_kill_jobs(C);
275
276         node = node_add_node(snode, bmain, scene, &ntemp, snode->mx, snode->my);
277
278         if (!node) {
279                 BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
280                 return OPERATOR_CANCELLED;
281         }
282
283         node->id = (ID *)ima;
284         id_us_plus(node->id);
285
286         snode_notify(C, snode);
287         snode_dag_update(C, snode);
288
289         return OPERATOR_FINISHED;
290 }
291
292 static int node_add_file_invoke(bContext *C, wmOperator *op, wmEvent *event)
293 {
294         ARegion *ar = CTX_wm_region(C);
295         SpaceNode *snode = CTX_wm_space_node(C);
296
297         /* convert mouse coordinates to v2d space */
298         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
299                                  &snode->mx, &snode->my);
300
301         if (RNA_struct_property_is_set(op->ptr, "filepath") || RNA_struct_property_is_set(op->ptr, "name"))
302                 return node_add_file_exec(C, op);
303         else
304                 return WM_operator_filesel(C, op, event);
305 }
306
307 void NODE_OT_add_file(wmOperatorType *ot)
308 {
309         /* identifiers */
310         ot->name = "Add File Node";
311         ot->description = "Add a file node to the current node editor";
312         ot->idname = "NODE_OT_add_file";
313
314         /* callbacks */
315         ot->exec = node_add_file_exec;
316         ot->invoke = node_add_file_invoke;
317         ot->poll = ED_operator_node_active;
318
319         /* flags */
320         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
321
322         WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE,
323                                        WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);  //XXX TODO, relative_path
324         RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
325 }
326
327
328 /********************** New node tree operator *********************/
329
330 static int new_node_tree_exec(bContext *C, wmOperator *op)
331 {
332         SpaceNode *snode;
333         bNodeTree *ntree;
334         PointerRNA ptr, idptr;
335         PropertyRNA *prop;
336         int treetype;
337         char treename[MAX_ID_NAME - 2] = "NodeTree";
338
339         /* retrieve state */
340         snode = CTX_wm_space_node(C);
341
342         if (RNA_struct_property_is_set(op->ptr, "type"))
343                 treetype = RNA_enum_get(op->ptr, "type");
344         else
345                 treetype = snode->treetype;
346
347         if (RNA_struct_property_is_set(op->ptr, "name"))
348                 RNA_string_get(op->ptr, "name", treename);
349
350         ntree = ntreeAddTree(treename, treetype, 0);
351         if (!ntree)
352                 return OPERATOR_CANCELLED;
353
354         /* hook into UI */
355         uiIDContextProperty(C, &ptr, &prop);
356
357         if (prop) {
358                 RNA_id_pointer_create(&ntree->id, &idptr);
359                 RNA_property_pointer_set(&ptr, prop, idptr);
360                 /* RNA_property_pointer_set increases the user count,
361                  * fixed here as the editor is the initial user.
362                  */
363                 --ntree->id.us;
364                 RNA_property_update(C, &ptr, prop);
365         }
366         else if (snode) {
367                 Scene *scene = CTX_data_scene(C);
368                 snode->nodetree = ntree;
369
370                 ED_node_tree_update(snode, scene);
371         }
372
373         return OPERATOR_FINISHED;
374 }
375
376 void NODE_OT_new_node_tree(wmOperatorType *ot)
377 {
378         /* identifiers */
379         ot->name = "New Node Tree";
380         ot->idname = "NODE_OT_new_node_tree";
381         ot->description = "Create a new node tree";
382
383         /* api callbacks */
384         ot->exec = new_node_tree_exec;
385         ot->poll = ED_operator_node_active;
386
387         /* flags */
388         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
389
390         RNA_def_enum(ot->srna, "type", nodetree_type_items, NTREE_COMPOSIT, "Tree Type", "");
391         RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME - 2, "Name", "");
392 }