code cleanup
[blender-staging.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
33 #include "DNA_lamp_types.h"
34 #include "DNA_material_types.h"
35 #include "DNA_node_types.h"
36 #include "DNA_world_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_math.h"
42
43 #include "BKE_context.h"
44 #include "BKE_screen.h"
45 #include "BKE_node.h"
46
47 #include "ED_space_api.h"
48 #include "ED_node.h"
49 #include "ED_render.h"
50 #include "ED_screen.h"
51 #include "ED_node.h"
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
57
58 #include "RNA_access.h"
59
60 #include "node_intern.h"  /* own include */
61
62
63 /* ******************** tree path ********************* */
64
65 void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
66 {
67         bNodeTreePath *path, *path_next;
68         for (path = snode->treepath.first; path; path = path_next) {
69                 path_next = path->next;
70                 MEM_freeN(path);
71         }
72         snode->treepath.first = snode->treepath.last = NULL;
73         
74         if (ntree) {
75                 path = MEM_callocN(sizeof(bNodeTreePath), "node tree path");
76                 path->nodetree = ntree;
77                 path->parent_key = NODE_INSTANCE_KEY_BASE;
78                 if (id)
79                         BLI_strncpy(path->node_name, id->name + 2, sizeof(path->node_name));
80                 BLI_addtail(&snode->treepath, path);
81         }
82         
83         /* update current tree */
84         snode->nodetree = snode->edittree = ntree;
85         snode->id = id;
86         snode->from = from;
87         
88         /* listener updates the View2D center from edittree */
89         WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
90 }
91
92 void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
93 {
94         bNodeTreePath *path = MEM_callocN(sizeof(bNodeTreePath), "node tree path");
95         bNodeTreePath *prev_path = snode->treepath.last;
96         path->nodetree = ntree;
97         if (gnode) {
98                 if (prev_path)
99                         path->parent_key = BKE_node_instance_key(prev_path->parent_key, prev_path->nodetree, gnode);
100                 else
101                         path->parent_key = NODE_INSTANCE_KEY_BASE;
102                 
103                 BLI_strncpy(path->node_name, gnode->name, sizeof(path->node_name));
104         }
105         else
106                 path->parent_key = NODE_INSTANCE_KEY_BASE;
107         
108         BLI_addtail(&snode->treepath, path);
109         
110         /* update current tree */
111         snode->edittree = ntree;
112         
113         /* listener updates the View2D center from edittree */
114         WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
115 }
116
117 void ED_node_tree_pop(SpaceNode *snode)
118 {
119         bNodeTreePath *path = snode->treepath.last;
120         
121         /* don't remove root */
122         if (path == snode->treepath.first)
123                 return;
124         
125         BLI_remlink(&snode->treepath, path);
126         MEM_freeN(path);
127         
128         /* update current tree */
129         path = snode->treepath.last;
130         snode->edittree = path->nodetree;
131         
132         /* listener updates the View2D center from edittree */
133         WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
134 }
135
136 int ED_node_tree_depth(SpaceNode *snode)
137 {
138         return BLI_countlist(&snode->treepath);
139 }
140
141 bNodeTree *ED_node_tree_get(SpaceNode *snode, int level)
142 {
143         bNodeTreePath *path;
144         int i;
145         for (path = snode->treepath.last, i = 0; path; path = path->prev, ++i) {
146                 if (i == level)
147                         return path->nodetree;
148         }
149         return NULL;
150 }
151
152 int ED_node_tree_path_length(SpaceNode *snode)
153 {
154         bNodeTreePath *path;
155         int length = 0;
156         int i;
157         for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
158                 length += strlen(path->node_name);
159                 if (i > 0)
160                         length += 1;    /* for separator char */
161         }
162         return length;
163 }
164
165 void ED_node_tree_path_get(SpaceNode *snode, char *value)
166 {
167         bNodeTreePath *path;
168         int i;
169         
170         value[0] = '\0';
171         for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
172                 if (i == 0) {
173                         strcpy(value, path->node_name);
174                         value += strlen(path->node_name);
175                 }
176                 else {
177                         sprintf(value, "/%s", path->node_name);
178                         value += strlen(path->node_name) + 1;
179                 }
180         }
181 }
182
183 void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_length)
184 {
185         bNodeTreePath *path;
186         int size, i;
187         
188         value[0] = '\0';
189         for (path = snode->treepath.first, i = 0; path; path = path->next, ++i) {
190                 if (i == 0) {
191                         BLI_strncpy(value, path->node_name, max_length);
192                         size = strlen(path->node_name);
193                 }
194                 else {
195                         BLI_snprintf(value, max_length, "/%s", path->node_name);
196                         size = strlen(path->node_name) + 1;
197                 }
198                 max_length -= size;
199                 if (max_length <= 0)
200                         break;
201                 value += size;
202         }
203 }
204
205 void snode_group_offset(SpaceNode *snode, float *x, float *y)
206 {
207         bNodeTreePath *path = snode->treepath.last;
208         float cx, cy;
209         
210         if (path) {
211                 cx = path->nodetree->view_center[0];
212                 cy = path->nodetree->view_center[1];
213                 
214                 if (path->prev) {
215                         *x = cx - path->prev->nodetree->view_center[0];
216                         *y = cy - path->prev->nodetree->view_center[1];
217                         return;
218                 }
219         }
220         
221         *x = *y = 0.0f;
222 }
223
224 /* ******************** manage regions ********************* */
225
226 ARegion *node_has_buttons_region(ScrArea *sa)
227 {
228         ARegion *ar, *arnew;
229
230         ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
231         if (ar) return ar;
232
233         /* add subdiv level; after header */
234         ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
235
236         /* is error! */
237         if (ar == NULL) return NULL;
238
239         arnew = MEM_callocN(sizeof(ARegion), "buttons for node");
240
241         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
242         arnew->regiontype = RGN_TYPE_UI;
243         arnew->alignment = RGN_ALIGN_RIGHT;
244
245         arnew->flag = RGN_FLAG_HIDDEN;
246
247         return arnew;
248 }
249
250 ARegion *node_has_tools_region(ScrArea *sa)
251 {
252         ARegion *ar, *arnew;
253         
254         ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
255         if (ar) return ar;
256         
257         /* add subdiv level; after header */
258         ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
259         
260         /* is error! */
261         if (ar == NULL) return NULL;
262         
263         arnew = MEM_callocN(sizeof(ARegion), "node tools");
264         
265         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
266         arnew->regiontype = RGN_TYPE_TOOLS;
267         arnew->alignment = RGN_ALIGN_LEFT;
268         
269         arnew->flag = RGN_FLAG_HIDDEN;
270         
271         return arnew;
272 }
273
274 /* ******************** default callbacks for node space ***************** */
275
276 static SpaceLink *node_new(const bContext *UNUSED(C))
277 {
278         ARegion *ar;
279         SpaceNode *snode;
280
281         snode = MEM_callocN(sizeof(SpaceNode), "initnode");
282         snode->spacetype = SPACE_NODE;
283
284         snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
285
286         /* backdrop */
287         snode->zoom = 1.0f;
288
289         /* select the first tree type for valid type */
290         NODE_TREE_TYPES_BEGIN(treetype)
291                 strcpy(snode->tree_idname, treetype->idname);
292                 break;
293         NODE_TREE_TYPES_END
294
295         /* header */
296         ar = MEM_callocN(sizeof(ARegion), "header for node");
297
298         BLI_addtail(&snode->regionbase, ar);
299         ar->regiontype = RGN_TYPE_HEADER;
300         ar->alignment = RGN_ALIGN_BOTTOM;
301
302         /* buttons/list view */
303         ar = MEM_callocN(sizeof(ARegion), "buttons for node");
304
305         BLI_addtail(&snode->regionbase, ar);
306         ar->regiontype = RGN_TYPE_UI;
307         ar->alignment = RGN_ALIGN_RIGHT;
308
309         /* main area */
310         ar = MEM_callocN(sizeof(ARegion), "main area for node");
311
312         BLI_addtail(&snode->regionbase, ar);
313         ar->regiontype = RGN_TYPE_WINDOW;
314
315         ar->v2d.tot.xmin =  -12.8f * U.widget_unit;
316         ar->v2d.tot.ymin =  -12.8f * U.widget_unit;
317         ar->v2d.tot.xmax = 38.4f * U.widget_unit;
318         ar->v2d.tot.ymax = 38.4f * U.widget_unit;
319
320         ar->v2d.cur =  ar->v2d.tot;
321
322         ar->v2d.min[0] = 1.0f;
323         ar->v2d.min[1] = 1.0f;
324
325         ar->v2d.max[0] = 32000.0f;
326         ar->v2d.max[1] = 32000.0f;
327
328         ar->v2d.minzoom = 0.09f;
329         ar->v2d.maxzoom = 2.31f;
330
331         ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
332         ar->v2d.keepzoom = V2D_LIMITZOOM | V2D_KEEPASPECT;
333         ar->v2d.keeptot = 0;
334
335         return (SpaceLink *)snode;
336 }
337
338 static void node_free(SpaceLink *sl)
339 {
340         SpaceNode *snode = (SpaceNode *)sl;
341         bNodeTreePath *path, *path_next;
342
343         for (path = snode->treepath.first; path; path = path_next) {
344                 path_next = path->next;
345                 MEM_freeN(path);
346         }
347 }
348
349
350 /* spacetype; init callback */
351 static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
352 {
353
354 }
355
356 static void node_area_listener(ScrArea *sa, wmNotifier *wmn)
357 {
358         /* note, ED_area_tag_refresh will re-execute compositor */
359         SpaceNode *snode = sa->spacedata.first;
360         short shader_type = snode->shaderfrom;
361
362         /* preview renders */
363         switch (wmn->category) {
364                 case NC_SCENE:
365                         switch (wmn->data) {
366                                 case ND_NODES: {
367                                         ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
368                                         /* shift view to node tree center */
369                                         if (ar && snode->edittree)
370                                                 UI_view2d_setcenter(&ar->v2d, snode->edittree->view_center[0], snode->edittree->view_center[1]);
371                                         
372                                         ED_area_tag_refresh(sa);
373                                         break;
374                                 }
375                                 case ND_FRAME:
376                                         ED_area_tag_refresh(sa);
377                                         break;
378                                 case ND_COMPO_RESULT:
379                                         ED_area_tag_redraw(sa);
380                                         break;
381                                 case ND_TRANSFORM_DONE:
382                                         if (ED_node_is_compositor(snode)) {
383                                                 if (snode->flag & SNODE_AUTO_RENDER) {
384                                                         snode->recalc = 1;
385                                                         ED_area_tag_refresh(sa);
386                                                 }
387                                         }
388                                         break;
389                         }
390                         break;
391
392                 /* future: add ID checks? */
393                 case NC_MATERIAL:
394                         if (ED_node_is_shader(snode)) {
395                                 if (wmn->data == ND_SHADING)
396                                         ED_area_tag_refresh(sa);
397                                 else if (wmn->data == ND_SHADING_DRAW)
398                                         ED_area_tag_refresh(sa);
399                                 else if (wmn->data == ND_SHADING_LINKS)
400                                         ED_area_tag_refresh(sa);
401                                 else if (wmn->action == NA_ADDED && snode->edittree)
402                                         nodeSetActiveID(snode->edittree, ID_MA, wmn->reference);
403
404                         }
405                         break;
406                 case NC_TEXTURE:
407                         if (ED_node_is_shader(snode) || ED_node_is_texture(snode)) {
408                                 if (wmn->data == ND_NODES)
409                                         ED_area_tag_refresh(sa);
410                         }
411                         break;
412                 case NC_WORLD:
413                         if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_WORLD) {
414                                 ED_area_tag_refresh(sa);
415                         }
416                         break;
417                 case NC_OBJECT:
418                         if (ED_node_is_shader(snode)) {
419                                 if (wmn->data == ND_OB_SHADING)
420                                         ED_area_tag_refresh(sa);
421                         }
422                         break;
423                 case NC_SPACE:
424                         if (wmn->data == ND_SPACE_NODE)
425                                 ED_area_tag_refresh(sa);
426                         else if (wmn->data == ND_SPACE_NODE_VIEW)
427                                 ED_area_tag_redraw(sa);
428                         break;
429                 case NC_NODE:
430                         if (wmn->action == NA_EDITED)
431                                 ED_area_tag_refresh(sa);
432                         else if (wmn->action == NA_SELECTED)
433                                 ED_area_tag_redraw(sa);
434                         break;
435                 case NC_SCREEN:
436                         switch (wmn->data) {
437                                 case ND_ANIMPLAY:
438                                         ED_area_tag_refresh(sa);
439                                         break;
440                         }
441                         break;
442                 case NC_MASK:
443                         if (wmn->action == NA_EDITED) {
444                                 if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) {
445                                         ED_area_tag_refresh(sa);
446                                 }
447                         }
448                         break;
449
450                 case NC_IMAGE:
451                         if (wmn->action == NA_EDITED) {
452                                 if (ED_node_is_compositor(snode)) {
453                                         /* note that nodeUpdateID is already called by BKE_image_signal() on all
454                                          * scenes so really this is just to know if the images is used in the compo else
455                                          * painting on images could become very slow when the compositor is open. */
456                                         if (nodeUpdateID(snode->nodetree, wmn->reference))
457                                                 ED_area_tag_refresh(sa);
458                                 }
459                         }
460                         break;
461
462                 case NC_MOVIECLIP:
463                         if (wmn->action == NA_EDITED) {
464                                 if (ED_node_is_compositor(snode)) {
465                                         if (nodeUpdateID(snode->nodetree, wmn->reference))
466                                                 ED_area_tag_refresh(sa);
467                                 }
468                         }
469                         break;
470         }
471 }
472
473 static void node_area_refresh(const struct bContext *C, ScrArea *sa)
474 {
475         /* default now: refresh node is starting preview */
476         SpaceNode *snode = sa->spacedata.first;
477         
478         ED_preview_kill_jobs(C);
479         
480         snode_set_context(C);
481
482         if (ntreeIsValid(snode->nodetree)) {
483                 if (snode->nodetree->type == NTREE_SHADER) {
484                         if (GS(snode->id->name) == ID_MA) {
485                                 Material *ma = (Material *)snode->id;
486                                 if (ma->use_nodes)
487                                         ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
488                         }
489                         else if (GS(snode->id->name) == ID_LA) {
490                                 Lamp *la = (Lamp *)snode->id;
491                                 if (la->use_nodes)
492                                         ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
493                         }
494                         else if (GS(snode->id->name) == ID_WO) {
495                                 World *wo = (World *)snode->id;
496                                 if (wo->use_nodes)
497                                         ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
498                         }
499                 }
500                 else if (snode->nodetree->type == NTREE_COMPOSIT) {
501                         Scene *scene = (Scene *)snode->id;
502                         if (scene->use_nodes) {
503                                 /* recalc is set on 3d view changes for auto compo */
504                                 if (snode->recalc) {
505                                         snode->recalc = 0;
506                                         node_render_changed_exec((struct bContext *)C, NULL);
507                                 }
508                                 else {
509                                         ED_node_composite_job(C, snode->nodetree, scene);
510                                 }
511                         }
512                 }
513                 else if (snode->nodetree->type == NTREE_TEXTURE) {
514                         Tex *tex = (Tex *)snode->id;
515                         if (tex->use_nodes) {
516                                 ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
517                         }
518                 }
519         }
520 }
521
522 static SpaceLink *node_duplicate(SpaceLink *sl)
523 {
524         SpaceNode *snode = (SpaceNode *)sl;
525         SpaceNode *snoden = MEM_dupallocN(snode);
526
527         /* clear or remove stuff from old */
528         snoden->nodetree = NULL;
529         snoden->linkdrag.first = snoden->linkdrag.last = NULL;
530         
531         BLI_duplicatelist(&snoden->treepath, &snode->treepath);
532
533         return (SpaceLink *)snoden;
534 }
535
536
537 /* add handlers, stuff you only do once or on area/region changes */
538 static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar)
539 {
540         wmKeyMap *keymap;
541
542         ED_region_panels_init(wm, ar);
543
544         keymap = WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
545         WM_event_add_keymap_handler(&ar->handlers, keymap);
546 }
547
548 static void node_buttons_area_draw(const bContext *C, ARegion *ar)
549 {
550         ED_region_panels(C, ar, 1, NULL, -1);
551 }
552
553 /* add handlers, stuff you only do once or on area/region changes */
554 static void node_toolbar_area_init(wmWindowManager *wm, ARegion *ar)
555 {
556         wmKeyMap *keymap;
557
558         ED_region_panels_init(wm, ar);
559
560         keymap = WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
561         WM_event_add_keymap_handler(&ar->handlers, keymap);
562 }
563
564 static void node_toolbar_area_draw(const bContext *C, ARegion *ar)
565 {
566         ED_region_panels(C, ar, 1, NULL, -1);
567 }
568
569 static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
570 {
571         SpaceNode *snode = sa->spacedata.first;
572
573         /* convert mouse coordinates to v2d space */
574         UI_view2d_region_to_view(&ar->v2d, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin,
575                                  &snode->cursor[0], &snode->cursor[1]);
576
577         node_set_cursor(win, snode);
578 }
579
580 /* Initialize main area, setting handlers. */
581 static void node_main_area_init(wmWindowManager *wm, ARegion *ar)
582 {
583         wmKeyMap *keymap;
584         ListBase *lb;
585
586         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
587
588         /* own keymaps */
589         keymap = WM_keymap_find(wm->defaultconf, "Node Generic", SPACE_NODE, 0);
590         WM_event_add_keymap_handler(&ar->handlers, keymap);
591
592         keymap = WM_keymap_find(wm->defaultconf, "Node Editor", SPACE_NODE, 0);
593         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
594
595         /* add drop boxes */
596         lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
597
598         WM_event_add_dropbox_handler(&ar->handlers, lb);
599 }
600
601 static void node_main_area_draw(const bContext *C, ARegion *ar)
602 {
603         drawnodespace(C, ar);
604 }
605
606
607 /* ************* dropboxes ************* */
608
609 static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
610 {
611         if (drag->type == WM_DRAG_ID) {
612                 ID *id = (ID *)drag->poin;
613                 if (GS(id->name) == ID_IM)
614                         return 1;
615         }
616         else if (drag->type == WM_DRAG_PATH) {
617                 if (ELEM(drag->icon, 0, ICON_FILE_IMAGE))   /* rule might not work? */
618                         return 1;
619         }
620         return 0;
621 }
622
623 static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
624 {
625         ID *id = (ID *)drag->poin;
626
627         if (id) {
628                 RNA_string_set(drop->ptr, "name", id->name + 2);
629         }
630         if (drag->path[0]) {
631                 RNA_string_set(drop->ptr, "filepath", drag->path);
632         }
633 }
634
635 /* this region dropbox definition */
636 static void node_dropboxes(void)
637 {
638         ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
639
640         WM_dropbox_add(lb, "NODE_OT_add_file", node_drop_poll, node_id_path_drop_copy);
641
642 }
643
644 /* ************* end drop *********** */
645
646
647 /* add handlers, stuff you only do once or on area/region changes */
648 static void node_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
649 {
650         ED_region_header_init(ar);
651 }
652
653 static void node_header_area_draw(const bContext *C, ARegion *ar)
654 {
655         /* find and set the context */
656         snode_set_context(C);
657
658         ED_region_header(C, ar);
659 }
660
661 /* used for header + main area */
662 static void node_region_listener(ARegion *ar, wmNotifier *wmn)
663 {
664         /* context changes */
665         switch (wmn->category) {
666                 case NC_SPACE:
667                         if (wmn->data == ND_SPACE_NODE)
668                                 ED_region_tag_redraw(ar);
669                         break;
670                 case NC_SCREEN:
671                         switch (wmn->data) {
672                                 case ND_SCREENCAST:
673                                 case ND_ANIMPLAY:
674                                         ED_region_tag_redraw(ar);
675                                         break;
676                         }
677                         break;
678                 case NC_SCENE:
679                 case NC_MATERIAL:
680                 case NC_TEXTURE:
681                 case NC_WORLD:
682                 case NC_NODE:
683                         ED_region_tag_redraw(ar);
684                         break;
685                 case NC_OBJECT:
686                         if (wmn->data == ND_OB_SHADING)
687                                 ED_region_tag_redraw(ar);
688                         break;
689                 case NC_ID:
690                         if (wmn->action == NA_RENAME)
691                                 ED_region_tag_redraw(ar);
692                         break;
693                 case NC_GPENCIL:
694                         if (wmn->action == NA_EDITED)
695                                 ED_region_tag_redraw(ar);
696                         break;
697         }
698 }
699
700 const char *node_context_dir[] = {"selected_nodes", "active_node", NULL};
701
702 static int node_context(const bContext *C, const char *member, bContextDataResult *result)
703 {
704         SpaceNode *snode = CTX_wm_space_node(C);
705
706         if (CTX_data_dir(member)) {
707                 CTX_data_dir_set(result, node_context_dir);
708                 return 1;
709         }
710         else if (CTX_data_equals(member, "selected_nodes")) {
711                 bNode *node;
712
713                 if (snode->edittree) {
714                         for (node = snode->edittree->nodes.last; node; node = node->prev) {
715                                 if (node->flag & NODE_SELECT) {
716                                         CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node);
717                                 }
718                         }
719                 }
720                 CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
721                 return 1;
722         }
723         else if (CTX_data_equals(member, "active_node")) {
724                 if (snode->edittree) {
725                         bNode *node = nodeGetActive(snode->edittree);
726                         CTX_data_pointer_set(result, &snode->edittree->id, &RNA_Node, node);
727                 }
728
729                 CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
730                 return 1;
731         }
732         else if (CTX_data_equals(member, "node_previews")) {
733                 if (snode->nodetree) {
734                         CTX_data_pointer_set(result, &snode->nodetree->id, &RNA_NodeInstanceHash, snode->nodetree->previews);
735                 }
736
737                 CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
738                 return 1;
739         }
740
741         return 0;
742 }
743
744 /* only called once, from space/spacetypes.c */
745 void ED_spacetype_node(void)
746 {
747         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype node");
748         ARegionType *art;
749
750         st->spaceid = SPACE_NODE;
751         strncpy(st->name, "Node", BKE_ST_MAXNAME);
752
753         st->new = node_new;
754         st->free = node_free;
755         st->init = node_init;
756         st->duplicate = node_duplicate;
757         st->operatortypes = node_operatortypes;
758         st->keymap = node_keymap;
759         st->listener = node_area_listener;
760         st->refresh = node_area_refresh;
761         st->context = node_context;
762         st->dropboxes = node_dropboxes;
763
764         /* regions: main window */
765         art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
766         art->regionid = RGN_TYPE_WINDOW;
767         art->init = node_main_area_init;
768         art->draw = node_main_area_draw;
769         art->listener = node_region_listener;
770         art->cursor = node_cursor;
771         art->event_cursor = TRUE;
772         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
773
774         BLI_addhead(&st->regiontypes, art);
775
776         /* regions: header */
777         art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
778         art->regionid = RGN_TYPE_HEADER;
779         art->prefsizey = HEADERY;
780         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
781         art->listener = node_region_listener;
782         art->init = node_header_area_init;
783         art->draw = node_header_area_draw;
784
785         BLI_addhead(&st->regiontypes, art);
786
787         node_menus_register();
788
789         /* regions: listview/buttons */
790         art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
791         art->regionid = RGN_TYPE_UI;
792         art->prefsizex = 180; // XXX
793         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
794         art->listener = node_region_listener;
795         art->init = node_buttons_area_init;
796         art->draw = node_buttons_area_draw;
797         BLI_addhead(&st->regiontypes, art);
798
799         node_buttons_register(art);
800
801         /* regions: toolbar */
802         art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
803         art->regionid = RGN_TYPE_TOOLS;
804         art->prefsizex = 160; /* XXX */
805         art->prefsizey = 50; /* XXX */
806         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
807         art->listener = node_region_listener;
808         art->init = node_toolbar_area_init;
809         art->draw = node_toolbar_area_draw;
810         BLI_addhead(&st->regiontypes, art);
811         
812         node_toolbar_register(art);
813
814         BKE_spacetype_register(st);
815 }
816