1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup spnode
22  */
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_anim_types.h"
27 #include "DNA_node_types.h"
28 
29 #include "BLI_blenlib.h"
30 #include "BLI_easing.h"
31 #include "BLI_math.h"
32 
33 #include "BKE_anim_data.h"
34 #include "BKE_context.h"
35 #include "BKE_lib_id.h"
36 #include "BKE_main.h"
37 #include "BKE_node.h"
38 
39 #include "ED_node.h" /* own include */
40 #include "ED_render.h"
41 #include "ED_screen.h"
42 #include "ED_util.h"
43 
44 #include "RNA_access.h"
45 #include "RNA_define.h"
46 
47 #include "WM_api.h"
48 #include "WM_types.h"
49 
50 #include "UI_resources.h"
51 #include "UI_view2d.h"
52 
53 #include "BLT_translation.h"
54 
55 #include "node_intern.h" /* own include */
56 
57 /* ****************** Relations helpers *********************** */
58 
ntree_has_drivers(bNodeTree * ntree)59 static bool ntree_has_drivers(bNodeTree *ntree)
60 {
61   AnimData *adt = BKE_animdata_from_id(&ntree->id);
62   if (adt == NULL) {
63     return false;
64   }
65   return !BLI_listbase_is_empty(&adt->drivers);
66 }
67 
ntree_check_nodes_connected_dfs(bNodeTree * ntree,bNode * from,bNode * to)68 static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to)
69 {
70   if (from->flag & NODE_TEST) {
71     return false;
72   }
73   from->flag |= NODE_TEST;
74   LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
75     if (link->fromnode == from) {
76       if (link->tonode == to) {
77         return true;
78       }
79 
80       if (ntree_check_nodes_connected_dfs(ntree, link->tonode, to)) {
81         return true;
82       }
83     }
84   }
85   return false;
86 }
87 
ntree_check_nodes_connected(bNodeTree * ntree,bNode * from,bNode * to)88 static bool ntree_check_nodes_connected(bNodeTree *ntree, bNode *from, bNode *to)
89 {
90   if (from == to) {
91     return true;
92   }
93   ntreeNodeFlagSet(ntree, NODE_TEST, false);
94   return ntree_check_nodes_connected_dfs(ntree, from, to);
95 }
96 
node_group_has_output_dfs(bNode * node)97 static bool node_group_has_output_dfs(bNode *node)
98 {
99   bNodeTree *ntree = (bNodeTree *)node->id;
100   if (ntree->id.tag & LIB_TAG_DOIT) {
101     return false;
102   }
103   ntree->id.tag |= LIB_TAG_DOIT;
104   for (bNode *current_node = ntree->nodes.first; current_node != NULL;
105        current_node = current_node->next) {
106     if (current_node->type == NODE_GROUP) {
107       if (current_node->id && node_group_has_output_dfs(current_node)) {
108         return true;
109       }
110     }
111     if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) {
112       return true;
113     }
114   }
115   return false;
116 }
117 
node_group_has_output(Main * bmain,bNode * node)118 static bool node_group_has_output(Main *bmain, bNode *node)
119 {
120   BLI_assert(ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP));
121   bNodeTree *ntree = (bNodeTree *)node->id;
122   if (ntree == NULL) {
123     return false;
124   }
125   BKE_main_id_tag_listbase(&bmain->nodetrees, LIB_TAG_DOIT, false);
126   return node_group_has_output_dfs(node);
127 }
128 
node_connected_to_output(Main * bmain,bNodeTree * ntree,bNode * node)129 bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node)
130 {
131   /* Special case for drivers: if node tree has any drivers we assume it is
132    * always to be tagged for update when node changes. Otherwise we will be
133    * doomed to do some deep and nasty deep search of indirect dependencies,
134    * which will be too complicated without real benefit.
135    */
136   if (ntree_has_drivers(ntree)) {
137     return true;
138   }
139   LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
140     /* Special case for group nodes -- if modified node connected to a group
141      * with active output inside we consider refresh is needed.
142      *
143      * We could make check more grained here by taking which socket the node
144      * is connected to and so eventually.
145      */
146     if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
147       if (current_node->id != NULL && ntree_has_drivers((bNodeTree *)current_node->id)) {
148         return true;
149       }
150       if (ntree_check_nodes_connected(ntree, node, current_node) &&
151           node_group_has_output(bmain, current_node)) {
152         return true;
153       }
154     }
155     if (current_node->flag & NODE_DO_OUTPUT) {
156       if (ntree_check_nodes_connected(ntree, node, current_node)) {
157         return true;
158       }
159     }
160   }
161   return false;
162 }
163 
164 /* ****************** Add *********************** */
165 
166 typedef struct bNodeListItem {
167   struct bNodeListItem *next, *prev;
168   struct bNode *node;
169 } bNodeListItem;
170 
171 typedef struct NodeInsertOfsData {
172   bNodeTree *ntree;
173   bNode *insert;      /* inserted node */
174   bNode *prev, *next; /* prev/next node in the chain */
175   bNode *insert_parent;
176 
177   wmTimer *anim_timer;
178 
179   float offset_x; /* offset to apply to node chain */
180 } NodeInsertOfsData;
181 
sort_nodes_locx(const void * a,const void * b)182 static int sort_nodes_locx(const void *a, const void *b)
183 {
184   const bNodeListItem *nli1 = a;
185   const bNodeListItem *nli2 = b;
186   const bNode *node1 = nli1->node;
187   const bNode *node2 = nli2->node;
188 
189   if (node1->locx > node2->locx) {
190     return 1;
191   }
192   return 0;
193 }
194 
socket_is_available(bNodeTree * UNUSED (ntree),bNodeSocket * sock,const bool allow_used)195 static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used)
196 {
197   if (nodeSocketIsHidden(sock)) {
198     return 0;
199   }
200 
201   if (!allow_used && (sock->flag & SOCK_IN_USE)) {
202     return 0;
203   }
204 
205   return 1;
206 }
207 
best_socket_output(bNodeTree * ntree,bNode * node,bNodeSocket * sock_target,const bool allow_multiple)208 static bNodeSocket *best_socket_output(bNodeTree *ntree,
209                                        bNode *node,
210                                        bNodeSocket *sock_target,
211                                        const bool allow_multiple)
212 {
213   /* first look for selected output */
214   LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
215     if (!socket_is_available(ntree, sock, allow_multiple)) {
216       continue;
217     }
218 
219     if (sock->flag & SELECT) {
220       return sock;
221     }
222   }
223 
224   /* try to find a socket with a matching name */
225   LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
226     if (!socket_is_available(ntree, sock, allow_multiple)) {
227       continue;
228     }
229 
230     /* check for same types */
231     if (sock->type == sock_target->type) {
232       if (STREQ(sock->name, sock_target->name)) {
233         return sock;
234       }
235     }
236   }
237 
238   /* otherwise settle for the first available socket of the right type */
239   LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
240     if (!socket_is_available(ntree, sock, allow_multiple)) {
241       continue;
242     }
243 
244     /* check for same types */
245     if (sock->type == sock_target->type) {
246       return sock;
247     }
248   }
249 
250   /* Always allow linking to an reroute node. The socket type of the reroute sockets might change
251    * after the link has been created. */
252   if (node->type == NODE_REROUTE) {
253     return node->outputs.first;
254   }
255 
256   return NULL;
257 }
258 
259 /* this is a bit complicated, but designed to prioritize finding
260  * sockets of higher types, such as image, first */
best_socket_input(bNodeTree * ntree,bNode * node,int num,int replace)261 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
262 {
263   int maxtype = 0;
264   LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
265     maxtype = max_ii(sock->type, maxtype);
266   }
267 
268   /* find sockets of higher 'types' first (i.e. image) */
269   int a = 0;
270   for (int socktype = maxtype; socktype >= 0; socktype--) {
271     LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
272       if (!socket_is_available(ntree, sock, replace)) {
273         a++;
274         continue;
275       }
276 
277       if (sock->type == socktype) {
278         /* increment to make sure we don't keep finding
279          * the same socket on every attempt running this function */
280         a++;
281         if (a > num) {
282           return sock;
283         }
284       }
285     }
286   }
287 
288   return NULL;
289 }
290 
snode_autoconnect_input(SpaceNode * snode,bNode * node_fr,bNodeSocket * sock_fr,bNode * node_to,bNodeSocket * sock_to,int replace)291 static bool snode_autoconnect_input(SpaceNode *snode,
292                                     bNode *node_fr,
293                                     bNodeSocket *sock_fr,
294                                     bNode *node_to,
295                                     bNodeSocket *sock_to,
296                                     int replace)
297 {
298   bNodeTree *ntree = snode->edittree;
299 
300   /* then we can connect */
301   if (replace) {
302     nodeRemSocketLinks(ntree, sock_to);
303   }
304 
305   nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
306   return true;
307 }
308 
snode_autoconnect(Main * bmain,SpaceNode * snode,const bool allow_multiple,const bool replace)309 static void snode_autoconnect(Main *bmain,
310                               SpaceNode *snode,
311                               const bool allow_multiple,
312                               const bool replace)
313 {
314   bNodeTree *ntree = snode->edittree;
315   ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
316 
317   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
318     if (node->flag & NODE_SELECT) {
319       bNodeListItem *nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
320       nli->node = node;
321       BLI_addtail(nodelist, nli);
322     }
323   }
324 
325   /* sort nodes left to right */
326   BLI_listbase_sort(nodelist, sort_nodes_locx);
327 
328   int numlinks = 0;
329   LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) {
330     bool has_selected_inputs = false;
331 
332     if (nli->next == NULL) {
333       break;
334     }
335 
336     bNode *node_fr = nli->node;
337     bNode *node_to = nli->next->node;
338     /* corner case: input/output node aligned the wrong way around (T47729) */
339     if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) {
340       SWAP(bNode *, node_fr, node_to);
341     }
342 
343     /* if there are selected sockets, connect those */
344     LISTBASE_FOREACH (bNodeSocket *, sock_to, &node_to->inputs) {
345       if (sock_to->flag & SELECT) {
346         has_selected_inputs = 1;
347 
348         if (!socket_is_available(ntree, sock_to, replace)) {
349           continue;
350         }
351 
352         /* check for an appropriate output socket to connect from */
353         bNodeSocket *sock_fr = best_socket_output(ntree, node_fr, sock_to, allow_multiple);
354         if (!sock_fr) {
355           continue;
356         }
357 
358         if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace)) {
359           numlinks++;
360         }
361       }
362     }
363 
364     if (!has_selected_inputs) {
365       /* no selected inputs, connect by finding suitable match */
366       int num_inputs = BLI_listbase_count(&node_to->inputs);
367 
368       for (int i = 0; i < num_inputs; i++) {
369 
370         /* find the best guess input socket */
371         bNodeSocket *sock_to = best_socket_input(ntree, node_to, i, replace);
372         if (!sock_to) {
373           continue;
374         }
375 
376         /* check for an appropriate output socket to connect from */
377         bNodeSocket *sock_fr = best_socket_output(ntree, node_fr, sock_to, allow_multiple);
378         if (!sock_fr) {
379           continue;
380         }
381 
382         if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace)) {
383           numlinks++;
384           break;
385         }
386       }
387     }
388   }
389 
390   if (numlinks > 0) {
391     ntreeUpdateTree(bmain, ntree);
392   }
393 
394   BLI_freelistN(nodelist);
395   MEM_freeN(nodelist);
396 }
397 
398 /* *************************** link viewer op ******************** */
399 
node_link_viewer(const bContext * C,bNode * tonode)400 static int node_link_viewer(const bContext *C, bNode *tonode)
401 {
402   SpaceNode *snode = CTX_wm_space_node(C);
403 
404   /* context check */
405   if (tonode == NULL || BLI_listbase_is_empty(&tonode->outputs)) {
406     return OPERATOR_CANCELLED;
407   }
408   if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
409     return OPERATOR_CANCELLED;
410   }
411 
412   /* get viewer */
413   bNode *viewer_node = NULL;
414   LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
415     if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
416       if (node->flag & NODE_DO_OUTPUT) {
417         viewer_node = node;
418         break;
419       }
420     }
421   }
422   /* no viewer, we make one active */
423   if (viewer_node == NULL) {
424     LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
425       if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
426         node->flag |= NODE_DO_OUTPUT;
427         viewer_node = node;
428         break;
429       }
430     }
431   }
432 
433   bNodeSocket *sock = NULL;
434   bNodeLink *link = NULL;
435 
436   /* try to find an already connected socket to cycle to the next */
437   if (viewer_node) {
438     link = NULL;
439 
440     for (link = snode->edittree->links.first; link; link = link->next) {
441       if (link->tonode == viewer_node && link->fromnode == tonode) {
442         if (link->tosock == viewer_node->inputs.first) {
443           break;
444         }
445       }
446     }
447     if (link) {
448       /* unlink existing connection */
449       sock = link->fromsock;
450       nodeRemLink(snode->edittree, link);
451 
452       /* find a socket after the previously connected socket */
453       for (sock = sock->next; sock; sock = sock->next) {
454         if (!nodeSocketIsHidden(sock)) {
455           break;
456         }
457       }
458     }
459   }
460 
461   if (tonode) {
462     /* Find a selected socket that overrides the socket to connect to */
463     LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
464       if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
465         sock = sock2;
466         break;
467       }
468     }
469   }
470 
471   /* find a socket starting from the first socket */
472   if (!sock) {
473     for (sock = tonode->outputs.first; sock; sock = sock->next) {
474       if (!nodeSocketIsHidden(sock)) {
475         break;
476       }
477     }
478   }
479 
480   if (sock) {
481     /* add a new viewer if none exists yet */
482     if (!viewer_node) {
483       /* XXX location is a quick hack, just place it next to the linked socket */
484       viewer_node = node_add_node(C, NULL, CMP_NODE_VIEWER, sock->locx + 100, sock->locy);
485       if (!viewer_node) {
486         return OPERATOR_CANCELLED;
487       }
488 
489       link = NULL;
490     }
491     else {
492       /* get link to viewer */
493       for (link = snode->edittree->links.first; link; link = link->next) {
494         if (link->tonode == viewer_node && link->tosock == viewer_node->inputs.first) {
495           break;
496         }
497       }
498     }
499 
500     if (link == NULL) {
501       nodeAddLink(snode->edittree, tonode, sock, viewer_node, viewer_node->inputs.first);
502     }
503     else {
504       link->fromnode = tonode;
505       link->fromsock = sock;
506       /* make sure the dependency sorting is updated */
507       snode->edittree->update |= NTREE_UPDATE_LINKS;
508     }
509     ntreeUpdateTree(CTX_data_main(C), snode->edittree);
510     snode_update(snode, viewer_node);
511   }
512 
513   return OPERATOR_FINISHED;
514 }
515 
node_active_link_viewer_exec(bContext * C,wmOperator * UNUSED (op))516 static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
517 {
518   SpaceNode *snode = CTX_wm_space_node(C);
519   bNode *node = nodeGetActive(snode->edittree);
520 
521   if (!node) {
522     return OPERATOR_CANCELLED;
523   }
524 
525   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
526 
527   if (node_link_viewer(C, node) == OPERATOR_CANCELLED) {
528     return OPERATOR_CANCELLED;
529   }
530 
531   snode_notify(C, snode);
532 
533   return OPERATOR_FINISHED;
534 }
535 
NODE_OT_link_viewer(wmOperatorType * ot)536 void NODE_OT_link_viewer(wmOperatorType *ot)
537 {
538   /* identifiers */
539   ot->name = "Link to Viewer Node";
540   ot->description = "Link to viewer node";
541   ot->idname = "NODE_OT_link_viewer";
542 
543   /* api callbacks */
544   ot->exec = node_active_link_viewer_exec;
545   ot->poll = composite_node_editable;
546 
547   /* flags */
548   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
549 }
550 
551 /* *************************** add link op ******************** */
552 
node_link_update_header(bContext * C,bNodeLinkDrag * UNUSED (nldrag))553 static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
554 {
555   char header[UI_MAX_DRAW_STR];
556 
557   BLI_strncpy(header, TIP_("LMB: drag node link, RMB: cancel"), sizeof(header));
558   ED_workspace_status_text(C, header);
559 }
560 
node_count_links(bNodeTree * ntree,bNodeSocket * sock)561 static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
562 {
563   int count = 0;
564   LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
565     if (link->fromsock == sock) {
566       count++;
567     }
568     if (link->tosock == sock) {
569       count++;
570     }
571   }
572   return count;
573 }
574 
node_remove_extra_links(SpaceNode * snode,bNodeLink * link)575 static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
576 {
577   bNodeTree *ntree = snode->edittree;
578   bNodeSocket *from = link->fromsock, *to = link->tosock;
579   int to_count = node_count_links(ntree, to);
580   int from_count = node_count_links(ntree, from);
581   int to_link_limit = nodeSocketLinkLimit(to);
582   int from_link_limit = nodeSocketLinkLimit(from);
583 
584   LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree->links) {
585     if (tlink == link) {
586       continue;
587     }
588 
589     if (tlink && tlink->fromsock == from) {
590       if (from_count > from_link_limit) {
591         nodeRemLink(ntree, tlink);
592         tlink = NULL;
593         from_count--;
594       }
595     }
596 
597     if (tlink && tlink->tosock == to) {
598       if (to_count > to_link_limit) {
599         nodeRemLink(ntree, tlink);
600         tlink = NULL;
601         to_count--;
602       }
603     }
604   }
605 }
606 
node_link_exit(bContext * C,wmOperator * op,bool apply_links)607 static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
608 {
609   Main *bmain = CTX_data_main(C);
610   SpaceNode *snode = CTX_wm_space_node(C);
611   bNodeTree *ntree = snode->edittree;
612   bNodeLinkDrag *nldrag = op->customdata;
613   bool do_tag_update = false;
614 
615   /* avoid updates while applying links */
616   ntree->is_updating = true;
617   LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
618     bNodeLink *link = linkdata->data;
619 
620     /* See note below, but basically TEST flag means that the link
621      * was connected to output (or to a node which affects the
622      * output).
623      */
624     do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
625 
626     if (apply_links && link->tosock && link->fromsock) {
627       /* before actually adding the link,
628        * let nodes perform special link insertion handling
629        */
630       if (link->fromnode->typeinfo->insert_link) {
631         link->fromnode->typeinfo->insert_link(ntree, link->fromnode, link);
632       }
633       if (link->tonode->typeinfo->insert_link) {
634         link->tonode->typeinfo->insert_link(ntree, link->tonode, link);
635       }
636 
637       /* add link to the node tree */
638       BLI_addtail(&ntree->links, link);
639 
640       ntree->update |= NTREE_UPDATE_LINKS;
641 
642       /* tag tonode for update */
643       link->tonode->update |= NODE_UPDATE;
644 
645       /* we might need to remove a link */
646       node_remove_extra_links(snode, link);
647 
648       if (link->tonode) {
649         do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, link->tonode));
650       }
651     }
652     else {
653       nodeRemLink(ntree, link);
654     }
655   }
656   ntree->is_updating = false;
657 
658   do_tag_update |= ED_node_is_simulation(snode);
659 
660   ntreeUpdateTree(bmain, ntree);
661   snode_notify(C, snode);
662   if (do_tag_update) {
663     snode_dag_update(C, snode);
664   }
665 
666   BLI_remlink(&snode->linkdrag, nldrag);
667   /* links->data pointers are either held by the tree or freed already */
668   BLI_freelistN(&nldrag->links);
669   MEM_freeN(nldrag);
670 }
671 
node_link_find_socket(bContext * C,wmOperator * op,float cursor[2])672 static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
673 {
674   SpaceNode *snode = CTX_wm_space_node(C);
675   bNodeLinkDrag *nldrag = op->customdata;
676 
677   if (nldrag->in_out == SOCK_OUT) {
678     bNode *tnode;
679     bNodeSocket *tsock = NULL;
680     if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
681       LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
682         bNodeLink *link = linkdata->data;
683 
684         /* skip if this is already the target socket */
685         if (link->tosock == tsock) {
686           continue;
687         }
688         /* skip if socket is on the same node as the fromsock */
689         if (tnode && link->fromnode == tnode) {
690           continue;
691         }
692 
693         /* attach links to the socket */
694         link->tonode = tnode;
695         link->tosock = tsock;
696       }
697     }
698     else {
699       LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
700         bNodeLink *link = linkdata->data;
701 
702         link->tonode = NULL;
703         link->tosock = NULL;
704       }
705     }
706   }
707   else {
708     bNode *tnode;
709     bNodeSocket *tsock = NULL;
710     if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
711       LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
712         bNodeLink *link = linkdata->data;
713 
714         /* skip if this is already the target socket */
715         if (link->fromsock == tsock) {
716           continue;
717         }
718         /* skip if socket is on the same node as the fromsock */
719         if (tnode && link->tonode == tnode) {
720           continue;
721         }
722 
723         /* attach links to the socket */
724         link->fromnode = tnode;
725         link->fromsock = tsock;
726       }
727     }
728     else {
729       LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) {
730         bNodeLink *link = linkdata->data;
731 
732         link->fromnode = NULL;
733         link->fromsock = NULL;
734       }
735     }
736   }
737 }
738 
739 /* loop that adds a nodelink, called by function below  */
740 /* in_out = starting socket */
node_link_modal(bContext * C,wmOperator * op,const wmEvent * event)741 static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
742 {
743   bNodeLinkDrag *nldrag = op->customdata;
744   ARegion *region = CTX_wm_region(C);
745   float cursor[2];
746 
747   UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
748 
749   switch (event->type) {
750     case MOUSEMOVE:
751       node_link_find_socket(C, op, cursor);
752 
753       node_link_update_header(C, nldrag);
754       ED_region_tag_redraw(region);
755       break;
756 
757     case LEFTMOUSE:
758     case RIGHTMOUSE:
759     case MIDDLEMOUSE: {
760       if (event->val == KM_RELEASE) {
761         node_link_exit(C, op, true);
762 
763         ED_workspace_status_text(C, NULL);
764         ED_region_tag_redraw(region);
765         return OPERATOR_FINISHED;
766       }
767       break;
768     }
769   }
770 
771   return OPERATOR_RUNNING_MODAL;
772 }
773 
774 /* return 1 when socket clicked */
node_link_init(Main * bmain,SpaceNode * snode,float cursor[2],bool detach)775 static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach)
776 {
777   bNodeLinkDrag *nldrag = NULL;
778 
779   /* output indicated? */
780   bNode *node;
781   bNodeSocket *sock;
782   if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
783     nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
784 
785     const int num_links = nodeCountSocketLinks(snode->edittree, sock);
786     int link_limit = nodeSocketLinkLimit(sock);
787     if (num_links > 0 && (num_links >= link_limit || detach)) {
788       /* dragged links are fixed on input side */
789       nldrag->in_out = SOCK_IN;
790       /* detach current links and store them in the operator data */
791       LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
792         if (link->fromsock == sock) {
793           LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
794           bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
795           linkdata->data = oplink;
796           *oplink = *link;
797           oplink->next = oplink->prev = NULL;
798           oplink->flag |= NODE_LINK_VALID;
799 
800           /* The link could be disconnected and in that case we
801            * wouldn't be able to check whether tag update is
802            * needed or not when releasing mouse button. So we
803            * cache whether the link affects output or not here
804            * using TEST flag.
805            */
806           oplink->flag &= ~NODE_LINK_TEST;
807           if (node_connected_to_output(bmain, snode->edittree, link->tonode)) {
808             oplink->flag |= NODE_LINK_TEST;
809           }
810 
811           BLI_addtail(&nldrag->links, linkdata);
812           nodeRemLink(snode->edittree, link);
813         }
814       }
815     }
816     else {
817       /* dragged links are fixed on output side */
818       nldrag->in_out = SOCK_OUT;
819       /* create a new link */
820       LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
821       bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
822       linkdata->data = oplink;
823       oplink->fromnode = node;
824       oplink->fromsock = sock;
825       oplink->flag |= NODE_LINK_VALID;
826       oplink->flag &= ~NODE_LINK_TEST;
827       if (node_connected_to_output(bmain, snode->edittree, node)) {
828         oplink->flag |= NODE_LINK_TEST;
829       }
830 
831       BLI_addtail(&nldrag->links, linkdata);
832     }
833   }
834   /* or an input? */
835   else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) {
836     nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
837 
838     const int num_links = nodeCountSocketLinks(snode->edittree, sock);
839     int link_limit = nodeSocketLinkLimit(sock);
840     if (num_links > 0 && (num_links >= link_limit || detach)) {
841       /* dragged links are fixed on output side */
842       nldrag->in_out = SOCK_OUT;
843       /* detach current links and store them in the operator data */
844       LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
845         if (link->tosock == sock) {
846           LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
847           bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
848           linkdata->data = oplink;
849           *oplink = *link;
850           oplink->next = oplink->prev = NULL;
851           oplink->flag |= NODE_LINK_VALID;
852           oplink->flag &= ~NODE_LINK_TEST;
853           if (node_connected_to_output(bmain, snode->edittree, link->tonode)) {
854             oplink->flag |= NODE_LINK_TEST;
855           }
856 
857           BLI_addtail(&nldrag->links, linkdata);
858           nodeRemLink(snode->edittree, link);
859 
860           /* send changed event to original link->tonode */
861           if (node) {
862             snode_update(snode, node);
863           }
864         }
865       }
866     }
867     else {
868       /* dragged links are fixed on input side */
869       nldrag->in_out = SOCK_IN;
870       /* create a new link */
871       LinkData *linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
872       bNodeLink *oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
873       linkdata->data = oplink;
874       oplink->tonode = node;
875       oplink->tosock = sock;
876       oplink->flag |= NODE_LINK_VALID;
877       oplink->flag &= ~NODE_LINK_TEST;
878       if (node_connected_to_output(bmain, snode->edittree, node)) {
879         oplink->flag |= NODE_LINK_TEST;
880       }
881 
882       BLI_addtail(&nldrag->links, linkdata);
883     }
884   }
885 
886   return nldrag;
887 }
888 
node_link_invoke(bContext * C,wmOperator * op,const wmEvent * event)889 static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
890 {
891   Main *bmain = CTX_data_main(C);
892   SpaceNode *snode = CTX_wm_space_node(C);
893   ARegion *region = CTX_wm_region(C);
894 
895   bool detach = RNA_boolean_get(op->ptr, "detach");
896 
897   float cursor[2];
898   UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
899 
900   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
901 
902   bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);
903 
904   if (nldrag) {
905     op->customdata = nldrag;
906     BLI_addtail(&snode->linkdrag, nldrag);
907 
908     /* add modal handler */
909     WM_event_add_modal_handler(C, op);
910 
911     return OPERATOR_RUNNING_MODAL;
912   }
913   return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
914 }
915 
node_link_cancel(bContext * C,wmOperator * op)916 static void node_link_cancel(bContext *C, wmOperator *op)
917 {
918   SpaceNode *snode = CTX_wm_space_node(C);
919   bNodeLinkDrag *nldrag = op->customdata;
920 
921   BLI_remlink(&snode->linkdrag, nldrag);
922 
923   BLI_freelistN(&nldrag->links);
924   MEM_freeN(nldrag);
925 }
926 
NODE_OT_link(wmOperatorType * ot)927 void NODE_OT_link(wmOperatorType *ot)
928 {
929   /* identifiers */
930   ot->name = "Link Nodes";
931   ot->idname = "NODE_OT_link";
932   ot->description = "Use the mouse to create a link between two nodes";
933 
934   /* api callbacks */
935   ot->invoke = node_link_invoke;
936   ot->modal = node_link_modal;
937   //  ot->exec = node_link_exec;
938   ot->poll = ED_operator_node_editable;
939   ot->cancel = node_link_cancel;
940 
941   /* flags */
942   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
943 
944   RNA_def_boolean(ot->srna, "detach", false, "Detach", "Detach and redirect existing links");
945 }
946 
947 /* ********************** Make Link operator ***************** */
948 
949 /* makes a link between selected output and input sockets */
node_make_link_exec(bContext * C,wmOperator * op)950 static int node_make_link_exec(bContext *C, wmOperator *op)
951 {
952   Main *bmain = CTX_data_main(C);
953   SpaceNode *snode = CTX_wm_space_node(C);
954   const bool replace = RNA_boolean_get(op->ptr, "replace");
955 
956   ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
957 
958   snode_autoconnect(bmain, snode, 1, replace);
959 
960   /* deselect sockets after linking */
961   node_deselect_all_input_sockets(snode, 0);
962   node_deselect_all_output_sockets(snode, 0);
963 
964   ntreeUpdateTree(CTX_data_main(C), snode->edittree);
965   snode_notify(C, snode);
966   snode_dag_update(C, snode);
967 
968   return OPERATOR_FINISHED;
969 }
970 
NODE_OT_link_make(wmOperatorType * ot)971 void NODE_OT_link_make(wmOperatorType *ot)
972 {
973   /* identifiers */
974   ot->name = "Make Links";
975   ot->description = "Makes a link between selected output in input sockets";
976   ot->idname = "NODE_OT_link_make";
977 
978   /* callbacks */
979   ot->exec = node_make_link_exec;
980   /* XXX we need a special poll which checks that there are selected input/output sockets. */
981   ot->poll = ED_operator_node_editable;
982 
983   /* flags */
984   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
985 
986   RNA_def_boolean(
987       ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
988 }
989 
990 /* ********************** Cut Link operator ***************** */
cut_links_intersect(bNodeLink * link,const float mcoords[][2],int tot)991 static bool cut_links_intersect(bNodeLink *link, const float mcoords[][2], int tot)
992 {
993   float coord_array[NODE_LINK_RESOL + 1][2];
994 
995   if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
996     for (int i = 0; i < tot - 1; i++) {
997       for (int b = 0; b < NODE_LINK_RESOL; b++) {
998         if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
999           return 1;
1000         }
1001       }
1002     }
1003   }
1004   return 0;
1005 }
1006 
cut_links_exec(bContext * C,wmOperator * op)1007 static int cut_links_exec(bContext *C, wmOperator *op)
1008 {
1009   Main *bmain = CTX_data_main(C);
1010   SpaceNode *snode = CTX_wm_space_node(C);
1011   ARegion *region = CTX_wm_region(C);
1012   bool do_tag_update = false;
1013 
1014   int i = 0;
1015   float mcoords[256][2];
1016   RNA_BEGIN (op->ptr, itemptr, "path") {
1017     float loc[2];
1018 
1019     RNA_float_get_array(&itemptr, "loc", loc);
1020     UI_view2d_region_to_view(
1021         &region->v2d, (int)loc[0], (int)loc[1], &mcoords[i][0], &mcoords[i][1]);
1022     i++;
1023     if (i >= 256) {
1024       break;
1025     }
1026   }
1027   RNA_END;
1028 
1029   if (i > 1) {
1030     bool found = false;
1031 
1032     ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1033 
1034     LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) {
1035       if (nodeLinkIsHidden(link)) {
1036         continue;
1037       }
1038 
1039       if (cut_links_intersect(link, mcoords, i)) {
1040 
1041         if (found == false) {
1042           /* TODO(sergey): Why did we kill jobs twice? */
1043           ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1044           found = true;
1045         }
1046 
1047         do_tag_update |= (do_tag_update ||
1048                           node_connected_to_output(bmain, snode->edittree, link->tonode));
1049 
1050         snode_update(snode, link->tonode);
1051         nodeRemLink(snode->edittree, link);
1052       }
1053     }
1054 
1055     do_tag_update |= ED_node_is_simulation(snode);
1056 
1057     if (found) {
1058       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1059       snode_notify(C, snode);
1060       if (do_tag_update) {
1061         snode_dag_update(C, snode);
1062       }
1063 
1064       return OPERATOR_FINISHED;
1065     }
1066 
1067     return OPERATOR_CANCELLED;
1068   }
1069 
1070   return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
1071 }
1072 
NODE_OT_links_cut(wmOperatorType * ot)1073 void NODE_OT_links_cut(wmOperatorType *ot)
1074 {
1075   ot->name = "Cut Links";
1076   ot->idname = "NODE_OT_links_cut";
1077   ot->description = "Use the mouse to cut (remove) some links";
1078 
1079   ot->invoke = WM_gesture_lines_invoke;
1080   ot->modal = WM_gesture_lines_modal;
1081   ot->exec = cut_links_exec;
1082   ot->cancel = WM_gesture_lines_cancel;
1083 
1084   ot->poll = ED_operator_node_editable;
1085 
1086   /* flags */
1087   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1088 
1089   /* properties */
1090   PropertyRNA *prop;
1091   prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
1092   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1093 
1094   /* internal */
1095   RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
1096 }
1097 
1098 /* ********************** Detach links operator ***************** */
1099 
detach_links_exec(bContext * C,wmOperator * UNUSED (op))1100 static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
1101 {
1102   SpaceNode *snode = CTX_wm_space_node(C);
1103   bNodeTree *ntree = snode->edittree;
1104 
1105   ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1106 
1107   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1108     if (node->flag & SELECT) {
1109       nodeInternalRelink(ntree, node);
1110     }
1111   }
1112 
1113   ntreeUpdateTree(CTX_data_main(C), ntree);
1114 
1115   snode_notify(C, snode);
1116   snode_dag_update(C, snode);
1117 
1118   return OPERATOR_FINISHED;
1119 }
1120 
NODE_OT_links_detach(wmOperatorType * ot)1121 void NODE_OT_links_detach(wmOperatorType *ot)
1122 {
1123   ot->name = "Detach Links";
1124   ot->idname = "NODE_OT_links_detach";
1125   ot->description =
1126       "Remove all links to selected nodes, and try to connect neighbor nodes together";
1127 
1128   ot->exec = detach_links_exec;
1129   ot->poll = ED_operator_node_editable;
1130 
1131   /* flags */
1132   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1133 }
1134 
1135 /* ****************** Set Parent ******************* */
1136 
node_parent_set_exec(bContext * C,wmOperator * UNUSED (op))1137 static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
1138 {
1139   SpaceNode *snode = CTX_wm_space_node(C);
1140   bNodeTree *ntree = snode->edittree;
1141   bNode *frame = nodeGetActive(ntree);
1142   if (!frame || frame->type != NODE_FRAME) {
1143     return OPERATOR_CANCELLED;
1144   }
1145 
1146   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1147     if (node == frame) {
1148       continue;
1149     }
1150     if (node->flag & NODE_SELECT) {
1151       nodeDetachNode(node);
1152       nodeAttachNode(node, frame);
1153     }
1154   }
1155 
1156   ED_node_sort(ntree);
1157   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1158 
1159   return OPERATOR_FINISHED;
1160 }
1161 
NODE_OT_parent_set(wmOperatorType * ot)1162 void NODE_OT_parent_set(wmOperatorType *ot)
1163 {
1164   /* identifiers */
1165   ot->name = "Make Parent";
1166   ot->description = "Attach selected nodes";
1167   ot->idname = "NODE_OT_parent_set";
1168 
1169   /* api callbacks */
1170   ot->exec = node_parent_set_exec;
1171   ot->poll = ED_operator_node_editable;
1172 
1173   /* flags */
1174   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1175 }
1176 
1177 /* ****************** Join Nodes ******************* */
1178 
1179 /* tags for depth-first search */
1180 #define NODE_JOIN_DONE 1
1181 #define NODE_JOIN_IS_DESCENDANT 2
1182 
node_join_attach_recursive(bNode * node,bNode * frame)1183 static void node_join_attach_recursive(bNode *node, bNode *frame)
1184 {
1185   node->done |= NODE_JOIN_DONE;
1186 
1187   if (node == frame) {
1188     node->done |= NODE_JOIN_IS_DESCENDANT;
1189   }
1190   else if (node->parent) {
1191     /* call recursively */
1192     if (!(node->parent->done & NODE_JOIN_DONE)) {
1193       node_join_attach_recursive(node->parent, frame);
1194     }
1195 
1196     /* in any case: if the parent is a descendant, so is the child */
1197     if (node->parent->done & NODE_JOIN_IS_DESCENDANT) {
1198       node->done |= NODE_JOIN_IS_DESCENDANT;
1199     }
1200     else if (node->flag & NODE_TEST) {
1201       /* if parent is not an descendant of the frame, reattach the node */
1202       nodeDetachNode(node);
1203       nodeAttachNode(node, frame);
1204       node->done |= NODE_JOIN_IS_DESCENDANT;
1205     }
1206   }
1207   else if (node->flag & NODE_TEST) {
1208     nodeAttachNode(node, frame);
1209     node->done |= NODE_JOIN_IS_DESCENDANT;
1210   }
1211 }
1212 
node_join_exec(bContext * C,wmOperator * UNUSED (op))1213 static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
1214 {
1215   SpaceNode *snode = CTX_wm_space_node(C);
1216   bNodeTree *ntree = snode->edittree;
1217 
1218   /* XXX save selection: node_add_node call below sets the new frame as single
1219    * active+selected node */
1220   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1221     if (node->flag & NODE_SELECT) {
1222       node->flag |= NODE_TEST;
1223     }
1224     else {
1225       node->flag &= ~NODE_TEST;
1226     }
1227   }
1228 
1229   bNode *frame = node_add_node(C, NULL, NODE_FRAME, 0.0f, 0.0f);
1230 
1231   /* reset tags */
1232   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1233     node->done = 0;
1234   }
1235 
1236   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1237     if (!(node->done & NODE_JOIN_DONE)) {
1238       node_join_attach_recursive(node, frame);
1239     }
1240   }
1241 
1242   /* restore selection */
1243   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1244     if (node->flag & NODE_TEST) {
1245       node->flag |= NODE_SELECT;
1246     }
1247   }
1248 
1249   ED_node_sort(ntree);
1250   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1251 
1252   return OPERATOR_FINISHED;
1253 }
1254 
NODE_OT_join(wmOperatorType * ot)1255 void NODE_OT_join(wmOperatorType *ot)
1256 {
1257   /* identifiers */
1258   ot->name = "Join Nodes";
1259   ot->description = "Attach selected nodes to a new common frame";
1260   ot->idname = "NODE_OT_join";
1261 
1262   /* api callbacks */
1263   ot->exec = node_join_exec;
1264   ot->poll = ED_operator_node_editable;
1265 
1266   /* flags */
1267   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1268 }
1269 
1270 /* ****************** Attach ******************* */
1271 
node_find_frame_to_attach(ARegion * region,const bNodeTree * ntree,const int mouse_xy[2])1272 static bNode *node_find_frame_to_attach(ARegion *region,
1273                                         const bNodeTree *ntree,
1274                                         const int mouse_xy[2])
1275 {
1276   /* convert mouse coordinates to v2d space */
1277   float cursor[2];
1278   UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
1279 
1280   LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree->nodes) {
1281     /* skip selected, those are the nodes we want to attach */
1282     if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) {
1283       continue;
1284     }
1285     if (BLI_rctf_isect_pt_v(&frame->totr, cursor)) {
1286       return frame;
1287     }
1288   }
1289 
1290   return NULL;
1291 }
1292 
node_attach_invoke(bContext * C,wmOperator * UNUSED (op),const wmEvent * event)1293 static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
1294 {
1295   ARegion *region = CTX_wm_region(C);
1296   SpaceNode *snode = CTX_wm_space_node(C);
1297   bNodeTree *ntree = snode->edittree;
1298   bNode *frame = node_find_frame_to_attach(region, ntree, event->mval);
1299 
1300   if (frame) {
1301     LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
1302       if (node->flag & NODE_SELECT) {
1303         if (node->parent == NULL) {
1304           /* disallow moving a parent into its child */
1305           if (nodeAttachNodeCheck(frame, node) == false) {
1306             /* attach all unparented nodes */
1307             nodeAttachNode(node, frame);
1308           }
1309         }
1310         else {
1311           /* attach nodes which share parent with the frame */
1312           bNode *parent;
1313           for (parent = frame->parent; parent; parent = parent->parent) {
1314             if (parent == node->parent) {
1315               break;
1316             }
1317           }
1318 
1319           if (parent) {
1320             /* disallow moving a parent into its child */
1321             if (nodeAttachNodeCheck(frame, node) == false) {
1322               nodeDetachNode(node);
1323               nodeAttachNode(node, frame);
1324             }
1325           }
1326         }
1327       }
1328     }
1329   }
1330 
1331   ED_node_sort(ntree);
1332   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1333 
1334   return OPERATOR_FINISHED;
1335 }
1336 
NODE_OT_attach(wmOperatorType * ot)1337 void NODE_OT_attach(wmOperatorType *ot)
1338 {
1339   /* identifiers */
1340   ot->name = "Attach Nodes";
1341   ot->description = "Attach active node to a frame";
1342   ot->idname = "NODE_OT_attach";
1343 
1344   /* api callbacks */
1345 
1346   ot->invoke = node_attach_invoke;
1347   ot->poll = ED_operator_node_editable;
1348 
1349   /* flags */
1350   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1351 }
1352 
1353 /* ****************** Detach ******************* */
1354 
1355 /* tags for depth-first search */
1356 #define NODE_DETACH_DONE 1
1357 #define NODE_DETACH_IS_DESCENDANT 2
1358 
node_detach_recursive(bNode * node)1359 static void node_detach_recursive(bNode *node)
1360 {
1361   node->done |= NODE_DETACH_DONE;
1362 
1363   if (node->parent) {
1364     /* call recursively */
1365     if (!(node->parent->done & NODE_DETACH_DONE)) {
1366       node_detach_recursive(node->parent);
1367     }
1368 
1369     /* in any case: if the parent is a descendant, so is the child */
1370     if (node->parent->done & NODE_DETACH_IS_DESCENDANT) {
1371       node->done |= NODE_DETACH_IS_DESCENDANT;
1372     }
1373     else if (node->flag & NODE_SELECT) {
1374       /* if parent is not a descendant of a selected node, detach */
1375       nodeDetachNode(node);
1376       node->done |= NODE_DETACH_IS_DESCENDANT;
1377     }
1378   }
1379   else if (node->flag & NODE_SELECT) {
1380     node->done |= NODE_DETACH_IS_DESCENDANT;
1381   }
1382 }
1383 
1384 /* detach the root nodes in the current selection */
node_detach_exec(bContext * C,wmOperator * UNUSED (op))1385 static int node_detach_exec(bContext *C, wmOperator *UNUSED(op))
1386 {
1387   SpaceNode *snode = CTX_wm_space_node(C);
1388   bNodeTree *ntree = snode->edittree;
1389 
1390   /* reset tags */
1391   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1392     node->done = 0;
1393   }
1394   /* detach nodes recursively
1395    * relative order is preserved here!
1396    */
1397   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1398     if (!(node->done & NODE_DETACH_DONE)) {
1399       node_detach_recursive(node);
1400     }
1401   }
1402 
1403   ED_node_sort(ntree);
1404   WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1405 
1406   return OPERATOR_FINISHED;
1407 }
1408 
NODE_OT_detach(wmOperatorType * ot)1409 void NODE_OT_detach(wmOperatorType *ot)
1410 {
1411   /* identifiers */
1412   ot->name = "Detach Nodes";
1413   ot->description = "Detach selected nodes from parents";
1414   ot->idname = "NODE_OT_detach";
1415 
1416   /* api callbacks */
1417   ot->exec = node_detach_exec;
1418   ot->poll = ED_operator_node_editable;
1419 
1420   /* flags */
1421   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1422 }
1423 
1424 /* *********************  automatic node insert on dragging ******************* */
1425 
1426 /* prevent duplicate testing code below */
ed_node_link_conditions(ScrArea * area,bool test,SpaceNode ** r_snode,bNode ** r_select)1427 static bool ed_node_link_conditions(ScrArea *area,
1428                                     bool test,
1429                                     SpaceNode **r_snode,
1430                                     bNode **r_select)
1431 {
1432   SpaceNode *snode = area ? area->spacedata.first : NULL;
1433 
1434   *r_snode = snode;
1435   *r_select = NULL;
1436 
1437   /* no unlucky accidents */
1438   if (area == NULL || area->spacetype != SPACE_NODE) {
1439     return false;
1440   }
1441 
1442   if (!test) {
1443     /* no need to look for a node */
1444     return true;
1445   }
1446 
1447   bNode *node;
1448   bNode *select = NULL;
1449   for (node = snode->edittree->nodes.first; node; node = node->next) {
1450     if (node->flag & SELECT) {
1451       if (select) {
1452         break;
1453       }
1454       select = node;
1455     }
1456   }
1457   /* only one selected */
1458   if (node || select == NULL) {
1459     return false;
1460   }
1461 
1462   /* correct node */
1463   if (BLI_listbase_is_empty(&select->inputs) || BLI_listbase_is_empty(&select->outputs)) {
1464     return false;
1465   }
1466 
1467   /* test node for links */
1468   LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
1469     if (nodeLinkIsHidden(link)) {
1470       continue;
1471     }
1472 
1473     if (link->tonode == select || link->fromnode == select) {
1474       return false;
1475     }
1476   }
1477 
1478   *r_select = select;
1479   return true;
1480 }
1481 
1482 /* test == 0, clear all intersect flags */
ED_node_link_intersect_test(ScrArea * area,int test)1483 void ED_node_link_intersect_test(ScrArea *area, int test)
1484 {
1485   bNode *select;
1486   SpaceNode *snode;
1487   if (!ed_node_link_conditions(area, test, &snode, &select)) {
1488     return;
1489   }
1490 
1491   /* clear flags */
1492   LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
1493     link->flag &= ~NODE_LINKFLAG_HILITE;
1494   }
1495 
1496   if (test == 0) {
1497     return;
1498   }
1499 
1500   /* find link to select/highlight */
1501   bNodeLink *selink = NULL;
1502   float dist_best = FLT_MAX;
1503   LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
1504     float coord_array[NODE_LINK_RESOL + 1][2];
1505 
1506     if (nodeLinkIsHidden(link)) {
1507       continue;
1508     }
1509 
1510     if (node_link_bezier_points(NULL, NULL, link, coord_array, NODE_LINK_RESOL)) {
1511       float dist = FLT_MAX;
1512 
1513       /* loop over link coords to find shortest dist to
1514        * upper left node edge of a intersected line segment */
1515       for (int i = 0; i < NODE_LINK_RESOL; i++) {
1516         /* check if the node rect intersetcts the line from this point to next one */
1517         if (BLI_rctf_isect_segment(&select->totr, coord_array[i], coord_array[i + 1])) {
1518           /* store the shortest distance to the upper left edge
1519            * of all intersections found so far */
1520           const float node_xy[] = {select->totr.xmin, select->totr.ymax};
1521 
1522           /* to be precise coord_array should be clipped by select->totr,
1523            * but not done since there's no real noticeable difference */
1524           dist = min_ff(
1525               dist_squared_to_line_segment_v2(node_xy, coord_array[i], coord_array[i + 1]), dist);
1526         }
1527       }
1528 
1529       /* we want the link with the shortest distance to node center */
1530       if (dist < dist_best) {
1531         dist_best = dist;
1532         selink = link;
1533       }
1534     }
1535   }
1536 
1537   if (selink) {
1538     selink->flag |= NODE_LINKFLAG_HILITE;
1539   }
1540 }
1541 
1542 /* assumes sockets in list */
socket_best_match(ListBase * sockets)1543 static bNodeSocket *socket_best_match(ListBase *sockets)
1544 {
1545   /* find type range */
1546   int maxtype = 0;
1547   LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
1548     maxtype = max_ii(sock->type, maxtype);
1549   }
1550 
1551   /* try all types, starting from 'highest' (i.e. colors, vectors, values) */
1552   for (int type = maxtype; type >= 0; type--) {
1553     LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
1554       if (!nodeSocketIsHidden(sock) && type == sock->type) {
1555         return sock;
1556       }
1557     }
1558   }
1559 
1560   /* no visible sockets, unhide first of highest type */
1561   for (int type = maxtype; type >= 0; type--) {
1562     LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
1563       if (type == sock->type) {
1564         sock->flag &= ~SOCK_HIDDEN;
1565         return sock;
1566       }
1567     }
1568   }
1569 
1570   return NULL;
1571 }
1572 
node_parents_offset_flag_enable_cb(bNode * parent,void * UNUSED (userdata))1573 static bool node_parents_offset_flag_enable_cb(bNode *parent, void *UNUSED(userdata))
1574 {
1575   /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
1576   parent->flag |= NODE_TEST;
1577 
1578   return true;
1579 }
1580 
node_offset_apply(bNode * node,const float offset_x)1581 static void node_offset_apply(bNode *node, const float offset_x)
1582 {
1583   /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
1584   if ((node->flag & NODE_TEST) == 0) {
1585     node->anim_init_locx = node->locx;
1586     node->anim_ofsx = (offset_x / UI_DPI_FAC);
1587     node->flag |= NODE_TEST;
1588   }
1589 }
1590 
node_parent_offset_apply(NodeInsertOfsData * data,bNode * parent,const float offset_x)1591 static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, const float offset_x)
1592 {
1593   node_offset_apply(parent, offset_x);
1594 
1595   /* Flag all children as offset to prevent them from being offset
1596    * separately (they've already moved with the parent). */
1597   LISTBASE_FOREACH (bNode *, node, &data->ntree->nodes) {
1598     if (nodeIsChildOf(parent, node)) {
1599       /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
1600       node->flag |= NODE_TEST;
1601     }
1602   }
1603 }
1604 
1605 #define NODE_INSOFS_ANIM_DURATION 0.25f
1606 
1607 /**
1608  * Callback that applies NodeInsertOfsData.offset_x to a node or its parent, similar
1609  * to node_link_insert_offset_output_chain_cb below, but with slightly different logic
1610  */
node_link_insert_offset_frame_chain_cb(bNode * fromnode,bNode * tonode,void * userdata,const bool reversed)1611 static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode,
1612                                                    bNode *tonode,
1613                                                    void *userdata,
1614                                                    const bool reversed)
1615 {
1616   NodeInsertOfsData *data = userdata;
1617   bNode *ofs_node = reversed ? fromnode : tonode;
1618 
1619   if (ofs_node->parent && ofs_node->parent != data->insert_parent) {
1620     node_offset_apply(ofs_node->parent, data->offset_x);
1621   }
1622   else {
1623     node_offset_apply(ofs_node, data->offset_x);
1624   }
1625 
1626   return true;
1627 }
1628 
1629 /**
1630  * Applies #NodeInsertOfsData.offset_x to all children of \a parent.
1631  */
node_link_insert_offset_frame_chains(const bNodeTree * ntree,const bNode * parent,NodeInsertOfsData * data,const bool reversed)1632 static void node_link_insert_offset_frame_chains(const bNodeTree *ntree,
1633                                                  const bNode *parent,
1634                                                  NodeInsertOfsData *data,
1635                                                  const bool reversed)
1636 {
1637   LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
1638     if (nodeIsChildOf(parent, node)) {
1639       nodeChainIter(ntree, node, node_link_insert_offset_frame_chain_cb, data, reversed);
1640     }
1641   }
1642 }
1643 
1644 /**
1645  * Callback that applies NodeInsertOfsData.offset_x to a node or its parent,
1646  * considering the logic needed for offsetting nodes after link insert
1647  */
node_link_insert_offset_chain_cb(bNode * fromnode,bNode * tonode,void * userdata,const bool reversed)1648 static bool node_link_insert_offset_chain_cb(bNode *fromnode,
1649                                              bNode *tonode,
1650                                              void *userdata,
1651                                              const bool reversed)
1652 {
1653   NodeInsertOfsData *data = userdata;
1654   bNode *ofs_node = reversed ? fromnode : tonode;
1655 
1656   if (data->insert_parent) {
1657     if (ofs_node->parent && (ofs_node->parent->flag & NODE_TEST) == 0) {
1658       node_parent_offset_apply(data, ofs_node->parent, data->offset_x);
1659       node_link_insert_offset_frame_chains(data->ntree, ofs_node->parent, data, reversed);
1660     }
1661     else {
1662       node_offset_apply(ofs_node, data->offset_x);
1663     }
1664 
1665     if (nodeIsChildOf(data->insert_parent, ofs_node) == false) {
1666       data->insert_parent = NULL;
1667     }
1668   }
1669   else if (ofs_node->parent) {
1670     bNode *node = nodeFindRootParent(ofs_node);
1671     node_offset_apply(node, data->offset_x);
1672   }
1673   else {
1674     node_offset_apply(ofs_node, data->offset_x);
1675   }
1676 
1677   return true;
1678 }
1679 
node_link_insert_offset_ntree(NodeInsertOfsData * iofsd,ARegion * region,const int mouse_xy[2],const bool right_alignment)1680 static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
1681                                           ARegion *region,
1682                                           const int mouse_xy[2],
1683                                           const bool right_alignment)
1684 {
1685   bNodeTree *ntree = iofsd->ntree;
1686   bNode *insert = iofsd->insert;
1687   bNode *prev = iofsd->prev, *next = iofsd->next;
1688   bNode *init_parent = insert->parent; /* store old insert->parent for restoring later */
1689 
1690   const float min_margin = U.node_margin * UI_DPI_FAC;
1691   const float width = NODE_WIDTH(insert);
1692   const bool needs_alignment = (next->totr.xmin - prev->totr.xmax) < (width + (min_margin * 2.0f));
1693 
1694   float margin = width;
1695 
1696   /* NODE_TEST will be used later, so disable for all nodes */
1697   ntreeNodeFlagSet(ntree, NODE_TEST, false);
1698 
1699   /* insert->totr isn't updated yet,
1700    * so totr_insert is used to get the correct worldspace coords */
1701   rctf totr_insert;
1702   node_to_updated_rect(insert, &totr_insert);
1703 
1704   /* frame attachment wasn't handled yet
1705    * so we search the frame that the node will be attached to later */
1706   insert->parent = node_find_frame_to_attach(region, ntree, mouse_xy);
1707 
1708   /* this makes sure nodes are also correctly offset when inserting a node on top of a frame
1709    * without actually making it a part of the frame (because mouse isn't intersecting it)
1710    * - logic here is similar to node_find_frame_to_attach */
1711   if (!insert->parent ||
1712       (prev->parent && (prev->parent == next->parent) && (prev->parent != insert->parent))) {
1713     bNode *frame;
1714     rctf totr_frame;
1715 
1716     /* check nodes front to back */
1717     for (frame = ntree->nodes.last; frame; frame = frame->prev) {
1718       /* skip selected, those are the nodes we want to attach */
1719       if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) {
1720         continue;
1721       }
1722 
1723       /* for some reason frame y coords aren't correct yet */
1724       node_to_updated_rect(frame, &totr_frame);
1725 
1726       if (BLI_rctf_isect_x(&totr_frame, totr_insert.xmin) &&
1727           BLI_rctf_isect_x(&totr_frame, totr_insert.xmax)) {
1728         if (BLI_rctf_isect_y(&totr_frame, totr_insert.ymin) ||
1729             BLI_rctf_isect_y(&totr_frame, totr_insert.ymax)) {
1730           /* frame isn't insert->parent actually, but this is needed to make offsetting
1731            * nodes work correctly for above checked cases (it is restored later) */
1732           insert->parent = frame;
1733           break;
1734         }
1735       }
1736     }
1737   }
1738 
1739   /* *** ensure offset at the left (or right for right_alignment case) of insert_node *** */
1740 
1741   float dist = right_alignment ? totr_insert.xmin - prev->totr.xmax :
1742                                  next->totr.xmin - totr_insert.xmax;
1743   /* distance between insert_node and prev is smaller than min margin */
1744   if (dist < min_margin) {
1745     const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
1746 
1747     node_offset_apply(insert, addval);
1748 
1749     totr_insert.xmin += addval;
1750     totr_insert.xmax += addval;
1751     margin += min_margin;
1752   }
1753 
1754   /* *** ensure offset at the right (or left for right_alignment case) of insert_node *** */
1755 
1756   dist = right_alignment ? next->totr.xmin - totr_insert.xmax : totr_insert.xmin - prev->totr.xmax;
1757   /* distance between insert_node and next is smaller than min margin */
1758   if (dist < min_margin) {
1759     const float addval = (min_margin - dist) * (right_alignment ? 1.0f : -1.0f);
1760     if (needs_alignment) {
1761       bNode *offs_node = right_alignment ? next : prev;
1762       if (!offs_node->parent || offs_node->parent == insert->parent ||
1763           nodeIsChildOf(offs_node->parent, insert)) {
1764         node_offset_apply(offs_node, addval);
1765       }
1766       else if (!insert->parent && offs_node->parent) {
1767         node_offset_apply(nodeFindRootParent(offs_node), addval);
1768       }
1769       margin = addval;
1770     }
1771     /* enough room is available, but we want to ensure the min margin at the right */
1772     else {
1773       /* offset inserted node so that min margin is kept at the right */
1774       node_offset_apply(insert, -addval);
1775     }
1776   }
1777 
1778   if (needs_alignment) {
1779     iofsd->insert_parent = insert->parent;
1780     iofsd->offset_x = margin;
1781 
1782     /* flag all parents of insert as offset to prevent them from being offset */
1783     nodeParentsIter(insert, node_parents_offset_flag_enable_cb, NULL);
1784     /* iterate over entire chain and apply offsets */
1785     nodeChainIter(ntree,
1786                   right_alignment ? next : prev,
1787                   node_link_insert_offset_chain_cb,
1788                   iofsd,
1789                   !right_alignment);
1790   }
1791 
1792   insert->parent = init_parent;
1793 }
1794 
1795 /**
1796  * Modal handler for insert offset animation
1797  */
node_insert_offset_modal(bContext * C,wmOperator * UNUSED (op),const wmEvent * event)1798 static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
1799 {
1800   SpaceNode *snode = CTX_wm_space_node(C);
1801   NodeInsertOfsData *iofsd = snode->iofsd;
1802   bool redraw = false;
1803 
1804   if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata) {
1805     return OPERATOR_PASS_THROUGH;
1806   }
1807 
1808   const float duration = (float)iofsd->anim_timer->duration;
1809 
1810   /* handle animation - do this before possibly aborting due to duration, since
1811    * main thread might be so busy that node hasn't reached final position yet */
1812   LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
1813     if (UNLIKELY(node->anim_ofsx)) {
1814       const float endval = node->anim_init_locx + node->anim_ofsx;
1815       if (IS_EQF(node->locx, endval) == false) {
1816         node->locx = BLI_easing_cubic_ease_in_out(
1817             duration, node->anim_init_locx, node->anim_ofsx, NODE_INSOFS_ANIM_DURATION);
1818         if (node->anim_ofsx < 0) {
1819           CLAMP_MIN(node->locx, endval);
1820         }
1821         else {
1822           CLAMP_MAX(node->locx, endval);
1823         }
1824         redraw = true;
1825       }
1826     }
1827   }
1828   if (redraw) {
1829     ED_region_tag_redraw(CTX_wm_region(C));
1830   }
1831 
1832   /* end timer + free insert offset data */
1833   if (duration > NODE_INSOFS_ANIM_DURATION) {
1834     WM_event_remove_timer(CTX_wm_manager(C), NULL, iofsd->anim_timer);
1835 
1836     LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
1837       node->anim_init_locx = node->anim_ofsx = 0.0f;
1838     }
1839 
1840     snode->iofsd = NULL;
1841     MEM_freeN(iofsd);
1842 
1843     return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
1844   }
1845 
1846   return OPERATOR_RUNNING_MODAL;
1847 }
1848 
1849 #undef NODE_INSOFS_ANIM_DURATION
1850 
node_insert_offset_invoke(bContext * C,wmOperator * op,const wmEvent * event)1851 static int node_insert_offset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1852 {
1853   const SpaceNode *snode = CTX_wm_space_node(C);
1854   NodeInsertOfsData *iofsd = snode->iofsd;
1855 
1856   if (!iofsd || !iofsd->insert) {
1857     return OPERATOR_CANCELLED;
1858   }
1859 
1860   BLI_assert((snode->flag & SNODE_SKIP_INSOFFSET) == 0);
1861 
1862   iofsd->ntree = snode->edittree;
1863   iofsd->anim_timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.02);
1864 
1865   node_link_insert_offset_ntree(
1866       iofsd, CTX_wm_region(C), event->mval, (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT));
1867 
1868   /* add temp handler */
1869   WM_event_add_modal_handler(C, op);
1870 
1871   return OPERATOR_RUNNING_MODAL;
1872 }
1873 
NODE_OT_insert_offset(wmOperatorType * ot)1874 void NODE_OT_insert_offset(wmOperatorType *ot)
1875 {
1876   /* identifiers */
1877   ot->name = "Insert Offset";
1878   ot->description = "Automatically offset nodes on insertion";
1879   ot->idname = "NODE_OT_insert_offset";
1880 
1881   /* callbacks */
1882   ot->invoke = node_insert_offset_invoke;
1883   ot->modal = node_insert_offset_modal;
1884   ot->poll = ED_operator_node_editable;
1885 
1886   /* flags */
1887   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1888 }
1889 
1890 /* assumes link with NODE_LINKFLAG_HILITE set */
ED_node_link_insert(Main * bmain,ScrArea * area)1891 void ED_node_link_insert(Main *bmain, ScrArea *area)
1892 {
1893   bNode *select;
1894   SpaceNode *snode;
1895   if (!ed_node_link_conditions(area, true, &snode, &select)) {
1896     return;
1897   }
1898 
1899   /* get the link */
1900   bNodeLink *link;
1901   for (link = snode->edittree->links.first; link; link = link->next) {
1902     if (link->flag & NODE_LINKFLAG_HILITE) {
1903       break;
1904     }
1905   }
1906 
1907   if (link) {
1908     bNodeSocket *best_input = socket_best_match(&select->inputs);
1909     bNodeSocket *best_output = socket_best_match(&select->outputs);
1910 
1911     if (best_input && best_output) {
1912       bNode *node = link->tonode;
1913       bNodeSocket *sockto = link->tosock;
1914 
1915       link->tonode = select;
1916       link->tosock = best_input;
1917       node_remove_extra_links(snode, link);
1918       link->flag &= ~NODE_LINKFLAG_HILITE;
1919 
1920       nodeAddLink(snode->edittree, select, best_output, node, sockto);
1921 
1922       /* set up insert offset data, it needs stuff from here */
1923       if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
1924         NodeInsertOfsData *iofsd = MEM_callocN(sizeof(NodeInsertOfsData), __func__);
1925 
1926         iofsd->insert = select;
1927         iofsd->prev = link->fromnode;
1928         iofsd->next = node;
1929 
1930         snode->iofsd = iofsd;
1931       }
1932 
1933       ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
1934       snode_update(snode, select);
1935       ED_node_tag_update_id(snode->id);
1936     }
1937   }
1938 }
1939