Merging r49281 through r49286 from trunk into soc-2011-tomato
[blender.git] / source / blender / editors / space_node / space_node.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/space_node.c
28  *  \ingroup spnode
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "DNA_lamp_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_node_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_world_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_math.h"
46 #include "BLI_rand.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_colortools.h"
50 #include "BKE_context.h"
51 #include "BKE_screen.h"
52 #include "BKE_node.h"
53
54 #include "ED_space_api.h"
55 #include "ED_render.h"
56 #include "ED_screen.h"
57
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 #include "UI_resources.h"
63 #include "UI_view2d.h"
64
65 #include "RNA_access.h"
66
67 #include "node_intern.h"    // own include
68
69 /* ******************** manage regions ********************* */
70
71 ARegion *node_has_buttons_region(ScrArea *sa)
72 {
73         ARegion *ar, *arnew;
74
75         ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
76         if (ar) return ar;
77
78         /* add subdiv level; after header */
79         ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
80
81         /* is error! */
82         if (ar == NULL) return NULL;
83
84         arnew = MEM_callocN(sizeof(ARegion), "buttons for node");
85
86         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
87         arnew->regiontype = RGN_TYPE_UI;
88         arnew->alignment = RGN_ALIGN_RIGHT;
89
90         arnew->flag = RGN_FLAG_HIDDEN;
91
92         return arnew;
93 }
94
95 /* ******************** default callbacks for node space ***************** */
96
97 static SpaceLink *node_new(const bContext *UNUSED(C))
98 {
99         ARegion *ar;
100         SpaceNode *snode;
101
102         snode = MEM_callocN(sizeof(SpaceNode), "initnode");
103         snode->spacetype = SPACE_NODE;
104
105         /* backdrop */
106         snode->zoom = 1.0f;
107
108         BKE_color_managed_view_settings_init(&snode->view_settings);
109
110         /* header */
111         ar = MEM_callocN(sizeof(ARegion), "header for node");
112
113         BLI_addtail(&snode->regionbase, ar);
114         ar->regiontype = RGN_TYPE_HEADER;
115         ar->alignment = RGN_ALIGN_BOTTOM;
116
117         /* buttons/list view */
118         ar = MEM_callocN(sizeof(ARegion), "buttons for node");
119
120         BLI_addtail(&snode->regionbase, ar);
121         ar->regiontype = RGN_TYPE_UI;
122         ar->alignment = RGN_ALIGN_RIGHT;
123         ar->flag = RGN_FLAG_HIDDEN;
124
125         /* main area */
126         ar = MEM_callocN(sizeof(ARegion), "main area for node");
127
128         BLI_addtail(&snode->regionbase, ar);
129         ar->regiontype = RGN_TYPE_WINDOW;
130
131         ar->v2d.tot.xmin =  -256.0f;
132         ar->v2d.tot.ymin =  -256.0f;
133         ar->v2d.tot.xmax = 768.0f;
134         ar->v2d.tot.ymax = 768.0f;
135
136         ar->v2d.cur.xmin =  -256.0f;
137         ar->v2d.cur.ymin =  -256.0f;
138         ar->v2d.cur.xmax = 768.0f;
139         ar->v2d.cur.ymax = 768.0f;
140
141         ar->v2d.min[0] = 1.0f;
142         ar->v2d.min[1] = 1.0f;
143
144         ar->v2d.max[0] = 32000.0f;
145         ar->v2d.max[1] = 32000.0f;
146
147         ar->v2d.minzoom = 0.09f;
148         ar->v2d.maxzoom = 2.31f;
149
150         ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
151         ar->v2d.keepzoom = V2D_LIMITZOOM | V2D_KEEPASPECT;
152         ar->v2d.keeptot = 0;
153
154         return (SpaceLink *)snode;
155 }
156
157 /* not spacelink itself */
158 static void node_free(SpaceLink *UNUSED(sl))
159 {
160
161 }
162
163
164 /* spacetype; init callback */
165 static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
166 {
167
168 }
169
170 static void node_area_listener(ScrArea *sa, wmNotifier *wmn)
171 {
172         /* note, ED_area_tag_refresh will re-execute compositor */
173         SpaceNode *snode = sa->spacedata.first;
174         int type = snode->treetype;
175         short shader_type = snode->shaderfrom;
176
177         /* preview renders */
178         switch (wmn->category) {
179                 case NC_SCENE:
180                         switch (wmn->data) {
181                                 case ND_NODES:
182                                 case ND_FRAME:
183                                         ED_area_tag_refresh(sa);
184                                         break;
185                                 case ND_COMPO_RESULT:
186                                         ED_area_tag_redraw(sa);
187                                         break;
188                                 case ND_TRANSFORM_DONE:
189                                         if (type == NTREE_COMPOSIT) {
190                                                 if (snode->flag & SNODE_AUTO_RENDER) {
191                                                         snode->recalc = 1;
192                                                         ED_area_tag_refresh(sa);
193                                                 }
194                                         }
195                                         break;
196                         }
197                         break;
198
199                 /* future: add ID checks? */
200                 case NC_MATERIAL:
201                         if (type == NTREE_SHADER) {
202                                 if (wmn->data == ND_SHADING)
203                                         ED_area_tag_refresh(sa);
204                                 else if (wmn->data == ND_SHADING_DRAW)
205                                         ED_area_tag_refresh(sa);
206                                 else if (wmn->action == NA_ADDED && snode->edittree)
207                                         nodeSetActiveID(snode->edittree, ID_MA, wmn->reference);
208
209                         }
210                         break;
211                 case NC_TEXTURE:
212                         if (type == NTREE_SHADER || type == NTREE_TEXTURE) {
213                                 if (wmn->data == ND_NODES)
214                                         ED_area_tag_refresh(sa);
215                         }
216                         break;
217                 case NC_WORLD:
218                         if (type == NTREE_SHADER && shader_type == SNODE_SHADER_WORLD) {
219                                 ED_area_tag_refresh(sa);
220                         }
221                         break;
222                 case NC_OBJECT:
223                         if (type == NTREE_SHADER) {
224                                 if (wmn->data == ND_OB_SHADING)
225                                         ED_area_tag_refresh(sa);
226                         }
227                         break;
228                 case NC_SPACE:
229                         if (wmn->data == ND_SPACE_NODE)
230                                 ED_area_tag_refresh(sa);
231                         else if (wmn->data == ND_SPACE_NODE_VIEW)
232                                 ED_area_tag_redraw(sa);
233                         break;
234                 case NC_NODE:
235                         if (wmn->action == NA_EDITED)
236                                 ED_area_tag_refresh(sa);
237                         else if (wmn->action == NA_SELECTED)
238                                 ED_area_tag_redraw(sa);
239                         break;
240                 case NC_SCREEN:
241                         switch (wmn->data) {
242                                 case ND_ANIMPLAY:
243                                         ED_area_tag_refresh(sa);
244                                         break;
245                         }
246                         break;
247                 case NC_MASK:
248                         if (wmn->action == NA_EDITED) {
249                                 if (type == NTREE_COMPOSIT) {
250                                         ED_area_tag_refresh(sa);
251                                 }
252                         }
253                         break;
254
255                 case NC_IMAGE:
256                         if (wmn->action == NA_EDITED) {
257                                 if (type == NTREE_COMPOSIT) {
258                                         /* note that nodeUpdateID is already called by BKE_image_signal() on all
259                                          * scenes so really this is just to know if the images is used in the compo else
260                                          * painting on images could become very slow when the compositor is open. */
261                                         if (nodeUpdateID(snode->nodetree, wmn->reference))
262                                                 ED_area_tag_refresh(sa);
263                                 }
264                         }
265                         break;
266         }
267 }
268
269 static void node_area_refresh(const struct bContext *C, ScrArea *sa)
270 {
271         /* default now: refresh node is starting preview */
272         SpaceNode *snode = sa->spacedata.first;
273
274         snode_set_context(snode, CTX_data_scene(C));
275
276         if (snode->nodetree) {
277                 if (snode->treetype == NTREE_SHADER) {
278                         if (GS(snode->id->name) == ID_MA) {
279                                 Material *ma = (Material *)snode->id;
280                                 if (ma->use_nodes)
281                                         ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
282                         }
283                         else if (GS(snode->id->name) == ID_LA) {
284                                 Lamp *la = (Lamp *)snode->id;
285                                 if (la->use_nodes)
286                                         ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
287                         }
288                         else if (GS(snode->id->name) == ID_WO) {
289                                 World *wo = (World *)snode->id;
290                                 if (wo->use_nodes)
291                                         ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
292                         }
293                 }
294                 else if (snode->treetype == NTREE_COMPOSIT) {
295                         Scene *scene = (Scene *)snode->id;
296                         if (scene->use_nodes) {
297                                 /* recalc is set on 3d view changes for auto compo */
298                                 if (snode->recalc) {
299                                         snode->recalc = 0;
300                                         node_render_changed_exec((struct bContext *)C, NULL);
301                                 }
302                                 else
303                                         snode_composite_job(C, sa);
304                         }
305                 }
306                 else if (snode->treetype == NTREE_TEXTURE) {
307                         Tex *tex = (Tex *)snode->id;
308                         if (tex->use_nodes) {
309                                 ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
310                         }
311                 }
312         }
313 }
314
315 static SpaceLink *node_duplicate(SpaceLink *sl)
316 {
317         SpaceImage *snode = (SpaceImage *) sl;
318         SpaceNode *snoden = MEM_dupallocN(sl);
319         
320         /* clear or remove stuff from old */
321         snoden->nodetree = NULL;
322         snoden->linkdrag.first = snoden->linkdrag.last = NULL;
323
324         BKE_color_managed_view_settings_copy(&snoden->view_settings, &snode->view_settings);
325
326         return (SpaceLink *)snoden;
327 }
328
329
330 /* add handlers, stuff you only do once or on area/region changes */
331 static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar)
332 {
333         wmKeyMap *keymap;
334
335         ED_region_panels_init(wm, ar);
336
337         keymap = WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
338         WM_event_add_keymap_handler(&ar->handlers, keymap);
339 }
340
341 static void node_buttons_area_draw(const bContext *C, ARegion *ar)
342 {
343         ED_region_panels(C, ar, 1, NULL, -1);
344 }
345
346 static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
347 {
348         SpaceNode *snode = sa->spacedata.first;
349
350         /* convert mouse coordinates to v2d space */
351         UI_view2d_region_to_view(&ar->v2d, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin,
352                                  &snode->mx, &snode->my);
353
354         node_set_cursor(win, snode);
355 }
356
357 /* Initialize main area, setting handlers. */
358 static void node_main_area_init(wmWindowManager *wm, ARegion *ar)
359 {
360         wmKeyMap *keymap;
361         ListBase *lb;
362
363         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
364
365         /* own keymaps */
366         keymap = WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
367         WM_event_add_keymap_handler(&ar->handlers, keymap);
368
369         keymap = WM_keymap_find(wm->defaultconf, "Node Editor", SPACE_NODE, 0);
370         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
371
372         /* add drop boxes */
373         lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
374
375         WM_event_add_dropbox_handler(&ar->handlers, lb);
376 }
377
378 static void node_main_area_draw(const bContext *C, ARegion *ar)
379 {
380         View2D *v2d = &ar->v2d;
381
382         drawnodespace(C, ar, v2d);
383 }
384
385
386 /* ************* dropboxes ************* */
387
388 static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
389 {
390         if (drag->type == WM_DRAG_ID) {
391                 ID *id = (ID *)drag->poin;
392                 if (GS(id->name) == ID_IM)
393                         return 1;
394         }
395         else if (drag->type == WM_DRAG_PATH) {
396                 if (ELEM(drag->icon, 0, ICON_FILE_IMAGE))   /* rule might not work? */
397                         return 1;
398         }
399         return 0;
400 }
401
402 static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
403 {
404         ID *id = (ID *)drag->poin;
405
406         if (id) {
407                 RNA_string_set(drop->ptr, "name", id->name + 2);
408         }
409         if (drag->path[0]) {
410                 RNA_string_set(drop->ptr, "filepath", drag->path);
411         }
412 }
413
414 /* this region dropbox definition */
415 static void node_dropboxes(void)
416 {
417         ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
418
419         WM_dropbox_add(lb, "NODE_OT_add_file", node_drop_poll, node_id_path_drop_copy);
420
421 }
422
423 /* ************* end drop *********** */
424
425
426 /* add handlers, stuff you only do once or on area/region changes */
427 static void node_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
428 {
429         ED_region_header_init(ar);
430 }
431
432 static void node_header_area_draw(const bContext *C, ARegion *ar)
433 {
434         SpaceNode *snode = CTX_wm_space_node(C);
435         Scene *scene = CTX_data_scene(C);
436
437         /* find and set the context */
438         snode_set_context(snode, scene);
439
440         ED_region_header(C, ar);
441 }
442
443 /* used for header + main area */
444 static void node_region_listener(ARegion *ar, wmNotifier *wmn)
445 {
446         /* context changes */
447         switch (wmn->category) {
448                 case NC_SPACE:
449                         if (wmn->data == ND_SPACE_NODE)
450                                 ED_region_tag_redraw(ar);
451                         break;
452                 case NC_SCREEN:
453                         switch (wmn->data) {
454                                 case ND_GPENCIL:
455                                         ED_region_tag_redraw(ar);
456                                         break;
457                                 case ND_SCREENCAST:
458                                 case ND_ANIMPLAY:
459                                         ED_region_tag_redraw(ar);
460                                         break;
461                         }
462                         break;
463                 case NC_SCENE:
464                 case NC_MATERIAL:
465                 case NC_TEXTURE:
466                 case NC_NODE:
467                         ED_region_tag_redraw(ar);
468                         break;
469                 case NC_OBJECT:
470                         if (wmn->data == ND_OB_SHADING)
471                                 ED_region_tag_redraw(ar);
472                         break;
473                 case NC_ID:
474                         if (wmn->action == NA_RENAME)
475                                 ED_region_tag_redraw(ar);
476                         break;
477         }
478 }
479
480 const char *node_context_dir[] = {"selected_nodes", "active_node", NULL};
481
482 static int node_context(const bContext *C, const char *member, bContextDataResult *result)
483 {
484         SpaceNode *snode = CTX_wm_space_node(C);
485
486         if (CTX_data_dir(member)) {
487                 CTX_data_dir_set(result, node_context_dir);
488                 return 1;
489         }
490         else if (CTX_data_equals(member, "selected_nodes")) {
491                 bNode *node;
492
493                 if (snode->edittree) {
494                         for (node = snode->edittree->nodes.last; node; node = node->prev) {
495                                 if (node->flag & NODE_SELECT) {
496                                         CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node);
497                                 }
498                         }
499                 }
500                 CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
501                 return 1;
502         }
503         else if (CTX_data_equals(member, "active_node")) {
504                 if (snode->edittree) {
505                         bNode *node = nodeGetActive(snode->edittree);
506                         CTX_data_pointer_set(result, &snode->edittree->id, &RNA_Node, node);
507                 }
508
509                 CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
510                 return 1;
511         }
512
513         return 0;
514 }
515
516 /* only called once, from space/spacetypes.c */
517 void ED_spacetype_node(void)
518 {
519         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype node");
520         ARegionType *art;
521
522         st->spaceid = SPACE_NODE;
523         strncpy(st->name, "Node", BKE_ST_MAXNAME);
524
525         st->new = node_new;
526         st->free = node_free;
527         st->init = node_init;
528         st->duplicate = node_duplicate;
529         st->operatortypes = node_operatortypes;
530         st->keymap = node_keymap;
531         st->listener = node_area_listener;
532         st->refresh = node_area_refresh;
533         st->context = node_context;
534         st->dropboxes = node_dropboxes;
535
536         /* regions: main window */
537         art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
538         art->regionid = RGN_TYPE_WINDOW;
539         art->init = node_main_area_init;
540         art->draw = node_main_area_draw;
541         art->listener = node_region_listener;
542         art->cursor = node_cursor;
543         art->event_cursor = TRUE;
544         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
545
546         BLI_addhead(&st->regiontypes, art);
547
548         /* regions: header */
549         art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
550         art->regionid = RGN_TYPE_HEADER;
551         art->prefsizey = HEADERY;
552         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
553         art->listener = node_region_listener;
554         art->init = node_header_area_init;
555         art->draw = node_header_area_draw;
556
557         BLI_addhead(&st->regiontypes, art);
558
559         node_menus_register();
560
561         /* regions: listview/buttons */
562         art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
563         art->regionid = RGN_TYPE_UI;
564         art->prefsizex = 180; // XXX
565         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
566         art->listener = node_region_listener;
567         art->init = node_buttons_area_init;
568         art->draw = node_buttons_area_draw;
569         BLI_addhead(&st->regiontypes, art);
570
571         node_buttons_register(art);
572
573         BKE_spacetype_register(st);
574 }
575