Node editor tweaks

* Cleaned up dead code, removed all traces of socket selection

* Modified border select so it's possible to have border select on mouse tweak.
With this change, by default, click+dragging on a node will select and move it, 
but click+dragging on empty space will border select.
This commit is contained in:
Matt Ebb 2010-01-06 03:00:19 +00:00
parent 7ec67dd43d
commit 4ba5b70d2f
7 changed files with 51 additions and 361 deletions

@ -531,20 +531,6 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
node->locx-= 0.5f*(min[0]+max[0]); node->locx-= 0.5f*(min[0]+max[0]);
node->locy-= 0.5f*(min[1]+max[1]); node->locy-= 0.5f*(min[1]+max[1]);
/* set selin and selout of the nodetree */
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) {
ngroup->selin= sock;
break;
}
}
for(sock= node->outputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) {
ngroup->selout= sock;
break;
}
}
/* set socket own_index to zero since it can still have a value /* set socket own_index to zero since it can still have a value
* from being in a group before, otherwise it doesn't get a unique * from being in a group before, otherwise it doesn't get a unique
* index in group_verify_own_indices */ * index in group_verify_own_indices */
@ -1134,28 +1120,6 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
node->flag &= ~(NODE_SELECT|NODE_ACTIVE); node->flag &= ~(NODE_SELECT|NODE_ACTIVE);
nnode->flag |= NODE_SELECT; nnode->flag |= NODE_SELECT;
} }
/* deselect original sockets */
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
}
for(sock= node->outputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
}
/* set tree selin and selout to new sockets */
for(sock= nnode->inputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) {
ntree->selin= sock;
break;
}
}
for(sock= nnode->outputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) {
ntree->selout= sock;
break;
}
}
} }
if(node==last) break; if(node==last) break;
} }

@ -2129,23 +2129,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
link->fromsock= newdataadr(fd, link->fromsock); link->fromsock= newdataadr(fd, link->fromsock);
link->tosock= newdataadr(fd, link->tosock); link->tosock= newdataadr(fd, link->tosock);
} }
/* set selin and selout */
for(node= ntree->nodes.first; node; node= node->next) {
for(sock= node->inputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) {
ntree->selin= sock;
break;
}
}
for(sock= node->outputs.first; sock; sock= sock->next) {
if(sock->flag & SOCK_SEL) {
ntree->selout= sock;
break;
}
}
}
/* type verification is in lib-link */ /* type verification is in lib-link */
} }

@ -506,9 +506,7 @@ static void socket_circle_draw(bNodeSocket *sock, float size)
/* choose color based on sock flags */ /* choose color based on sock flags */
if(sock->flag & SELECT) { if(sock->flag & SELECT) {
if(sock->flag & SOCK_SEL) { if(sock->type==SOCK_VALUE) {
col[0]= 240; col[1]= 200; col[2]= 40;}
else if(sock->type==SOCK_VALUE) {
col[0]= 200; col[1]= 200; col[2]= 200;} col[0]= 200; col[1]= 200; col[2]= 200;}
else if(sock->type==SOCK_VECTOR) { else if(sock->type==SOCK_VECTOR) {
col[0]= 140; col[1]= 140; col[2]= 240;} col[0]= 140; col[1]= 140; col[2]= 240;}
@ -517,8 +515,6 @@ static void socket_circle_draw(bNodeSocket *sock, float size)
else { else {
col[0]= 140; col[1]= 240; col[2]= 140;} col[0]= 140; col[1]= 240; col[2]= 140;}
} }
else if(sock->flag & SOCK_SEL) {
col[0]= 200; col[1]= 160; col[2]= 0;}
else { else {
if(sock->type==-1) { if(sock->type==-1) {
col[0]= 0; col[1]= 0; col[2]= 0;} col[0]= 0; col[1]= 0; col[2]= 0;}

@ -222,116 +222,6 @@ void snode_handle_recalc(bContext *C, SpaceNode *snode)
WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id); WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id);
} }
#if 0
static int image_detect_file_sequence(int *start_p, int *frames_p, char *str)
{
SpaceFile *sfile;
char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX], filename[FILE_MAX];
int a, frame, totframe, found, minframe;
unsigned short numlen;
sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
if(sfile==NULL || sfile->filelist==NULL)
return 0;
/* find first frame */
found= 0;
minframe= 0;
for(a=0; a<sfile->totfile; a++) {
if(sfile->filelist[a].flags & ACTIVE) {
BLI_strncpy(name, sfile->filelist[a].relname, sizeof(name));
frame= BLI_stringdec(name, head, tail, &numlen);
if(!found || frame < minframe) {
BLI_strncpy(filename, name, sizeof(name));
minframe= frame;
found= 1;
}
}
}
/* not one frame found */
if(!found)
return 0;
/* counter number of following frames */
found= 1;
totframe= 0;
for(frame=minframe; found; frame++) {
found= 0;
BLI_strncpy(name, filename, sizeof(name));
BLI_stringenc(name, head, tail, numlen, frame);
for(a=0; a<sfile->totfile; a++) {
if(sfile->filelist[a].flags & ACTIVE) {
if(strcmp(sfile->filelist[a].relname, name) == 0) {
found= 1;
totframe++;
break;
}
}
}
}
if(totframe > 1) {
BLI_strncpy(str, sfile->dir, sizeof(name));
strcat(str, filename);
*start_p= minframe;
*frames_p= totframe;
return 1;
}
return 0;
}
static void load_node_image(char *str) /* called from fileselect */
{
SpaceNode *snode= curarea->spacedata.first;
bNode *node= nodeGetActive(snode->edittree);
Image *ima= NULL;
ImageUser *iuser= node->storage;
char filename[FILE_MAX];
int start=0, frames=0, sequence;
sequence= image_detect_file_sequence(&start, &frames, filename);
if(sequence)
str= filename;
ima= BKE_add_image_file(str);
if(ima) {
if(node->id)
node->id->us--;
node->id= &ima->id;
id_us_plus(node->id);
BLI_strncpy(node->name, node->id->name+2, 21);
if(sequence) {
ima->source= IMA_SRC_SEQUENCE;
iuser->frames= frames;
iuser->offset= start-1;
}
BKE_image_signal(ima, node->storage, IMA_SIGNAL_RELOAD);
NodeTagChanged(snode->edittree, node);
// XXX snode_handle_recalc(C, snode);
}
}
static void set_node_imagepath(char *str) /* called from fileselect */
{
SpaceNode *snode= curarea->spacedata.first;
bNode *node= nodeGetActive(snode->edittree);
BLI_strncpy(((NodeImageFile *)node->storage)->name, str, sizeof( ((NodeImageFile *)node->storage)->name ));
}
#endif /* 0 */
bNode *node_tree_get_editgroup(bNodeTree *nodetree) bNode *node_tree_get_editgroup(bNodeTree *nodetree)
{ {
bNode *gnode; bNode *gnode;
@ -343,93 +233,6 @@ bNode *node_tree_get_editgroup(bNodeTree *nodetree)
return gnode; return gnode;
} }
#if 0
static void composit_node_event(SpaceNode *snode, short event)
{
switch(event) {
case B_REDR:
// allqueue(REDRAWNODE, 1);
break;
case B_NODE_SETIMAGE:
{
bNode *node= nodeGetActive(snode->edittree);
char name[FILE_MAXDIR+FILE_MAXFILE];
strcpy(name, ((NodeImageFile *)node->storage)->name);
if (G.qual & LR_CTRLKEY) {
activate_imageselect(FILE_SPECIAL, "SELECT OUTPUT DIR", name, set_node_imagepath);
} else {
activate_fileselect(FILE_SPECIAL, "SELECT OUTPUT DIR", name, set_node_imagepath);
}
break;
}
case B_NODE_TREE_EXEC:
// XXX snode_handle_recalc(snode);
break;
default:
/* B_NODE_EXEC */
{
bNode *node= BLI_findlink(&snode->edittree->nodes, event-B_NODE_EXEC);
if(node) {
NodeTagChanged(snode->edittree, node);
/* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
/* not the best implementation of the world... but we need it to work now :) */
if(node->type==CMP_NODE_R_LAYERS && node->custom2) {
/* add event for this window (after render curarea can be changed) */
addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
composite_node_render(snode, node);
// XXX snode_handle_recalc(snode);
/* add another event, a render can go fullscreen and open new window */
addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
}
else {
node= node_tree_get_editgroup(snode->nodetree);
if(node)
NodeTagIDChanged(snode->nodetree, node->id);
// XXX snode_handle_recalc(snode);
}
}
}
}
}
static void texture_node_event(SpaceNode *snode, short event)
{
switch(event) {
case B_REDR:
// allqueue(REDRAWNODE, 1);
break;
case B_NODE_LOADIMAGE:
{
bNode *node= nodeGetActive(snode->edittree);
char name[FILE_MAXDIR+FILE_MAXFILE];
if(node->id)
strcpy(name, ((Image *)node->id)->name);
else strcpy(name, U.textudir);
if (G.qual & LR_CTRLKEY) {
activate_imageselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
} else {
activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
}
break;
}
default:
/* B_NODE_EXEC */
ntreeTexCheckCyclics( snode->nodetree );
// XXX snode_handle_recalc(snode);
// allqueue(REDRAWNODE, 1);
break;
}
}
#endif /* 0 */
/* assumes nothing being done in ntree yet, sets the default in/out node */ /* assumes nothing being done in ntree yet, sets the default in/out node */
/* called from shading buttons or header */ /* called from shading buttons or header */
void ED_node_shader_default(Material *ma) void ED_node_shader_default(Material *ma)
@ -620,29 +423,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene)
node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
} }
#if 0
/* on activate image viewer, check if we show it */
static void node_active_image(Image *ima)
{
ScrArea *sa;
SpaceImage *sima= NULL;
/* find an imagewindow showing render result */
for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
if(sa->spacetype==SPACE_IMAGE) {
sima= sa->spacedata.first;
if(sima->image && sima->image->source!=IMA_SRC_VIEWER)
break;
}
}
if(sa && sima) {
sima->image= ima;
scrarea_queue_winredraw(sa);
scrarea_queue_headredraw(sa);
}
}
#endif /* 0 */
void node_set_active(SpaceNode *snode, bNode *node) void node_set_active(SpaceNode *snode, bNode *node)
{ {
nodeSetActive(snode->edittree, node); nodeSetActive(snode->edittree, node);
@ -692,18 +472,9 @@ void node_set_active(SpaceNode *snode, bNode *node)
/* addnode() doesnt link this yet... */ /* addnode() doesnt link this yet... */
node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
} }
else if(node->type==CMP_NODE_IMAGE) {
// XXX
#if 0
if(node->id)
node_active_image((Image *)node->id);
#endif
}
else if(node->type==CMP_NODE_R_LAYERS) { else if(node->type==CMP_NODE_R_LAYERS) {
if(node->id==NULL || node->id==(ID *)scene) { if(node->id==NULL || node->id==(ID *)scene) {
scene->r.actlay= node->custom1; scene->r.actlay= node->custom1;
// XXX
// allqueue(REDRAWBUTSSCENE, 0);
} }
} }
} }
@ -765,13 +536,6 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
snode->edittree= snode->nodetree; snode->edittree= snode->nodetree;
ntreeSolveOrder(snode->nodetree); ntreeSolveOrder(snode->nodetree);
/* finally send out events for new active node */
if(snode->treetype==NTREE_SHADER) {
// allqueue(REDRAWBUTSSHADING, 0);
// XXX BIF_preview_changed(-1); /* temp hack to force texture preview to update */
}
} }
static int node_group_edit_exec(bContext *C, wmOperator *op) static int node_group_edit_exec(bContext *C, wmOperator *op)
@ -1096,31 +860,8 @@ void NODE_OT_resize(wmOperatorType *ot)
ot->flag= OPTYPE_BLOCKING; ot->flag= OPTYPE_BLOCKING;
} }
#if 0
/* ********************** select ******************** */ /* ********************** select ******************** */
/* used in buttons to check context, also checks for edited groups */
bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
{
return nodeGetActiveID(ntree, id_code);
}
/* used in buttons to check context, also checks for edited groups */
Material *editnode_get_active_material(Material *ma)
{
if(ma && ma->use_nodes && ma->nodetree) {
bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
if(node)
return (Material *)node->id;
else
return NULL;
}
return ma;
}
#endif /* 0 */
/* no undo here! */ /* no undo here! */
void node_deselectall(SpaceNode *snode) void node_deselectall(SpaceNode *snode)
@ -1172,8 +913,6 @@ static void node_link_viewer(SpaceNode *snode, bNode *tonode)
link->fromnode= tonode; link->fromnode= tonode;
link->fromsock= tonode->outputs.first; link->fromsock= tonode->outputs.first;
NodeTagChanged(snode->edittree, node); NodeTagChanged(snode->edittree, node);
// XXX snode_handle_recalc(snode);
} }
} }
} }
@ -1559,24 +1298,6 @@ typedef struct NodeLinkDrag
int in_out; int in_out;
} NodeLinkDrag; } NodeLinkDrag;
/*static*/ void reset_sel_socket(SpaceNode *snode, int in_out)
{
bNode *node;
bNodeSocket *sock;
for(node= snode->edittree->nodes.first; node; node= node->next) {
if(in_out & SOCK_IN) {
for(sock= node->inputs.first; sock; sock= sock->next)
if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
}
if(in_out & SOCK_OUT) {
for(sock= node->outputs.first; sock; sock= sock->next)
if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
}
}
}
static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link) static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
{ {
bNodeLink *tlink; bNodeLink *tlink;
@ -2125,18 +1846,10 @@ static int node_delete_exec(bContext *C, wmOperator *op)
{ {
SpaceNode *snode= CTX_wm_space_node(C); SpaceNode *snode= CTX_wm_space_node(C);
bNode *node, *next; bNode *node, *next;
bNodeSocket *sock;
for(node= snode->edittree->nodes.first; node; node= next) { for(node= snode->edittree->nodes.first; node; node= next) {
next= node->next; next= node->next;
if(node->flag & SELECT) { if(node->flag & SELECT) {
/* set selin and selout NULL if the sockets belong to a node to be deleted */
for(sock= node->inputs.first; sock; sock= sock->next)
if(snode->edittree->selin == sock) snode->edittree->selin= NULL;
for(sock= node->outputs.first; sock; sock= sock->next)
if(snode->edittree->selout == sock) snode->edittree->selout= NULL;
/* check id user here, nodeFreeNode is called for free dbase too */ /* check id user here, nodeFreeNode is called for free dbase too */
if(node->id) if(node->id)
node->id->us--; node->id->us--;

@ -109,6 +109,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "extend", 1); RNA_boolean_set(kmi->ptr, "extend", 1);
kmi= WM_keymap_add_item(keymap, "NODE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); kmi= WM_keymap_add_item(keymap, "NODE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1); RNA_boolean_set(kmi->ptr, "extend", 1);
RNA_boolean_set(WM_keymap_add_item(keymap, "NODE_OT_select_border", EVT_TWEAK_S, KM_ANY, 0, 0)->ptr, "tweak", 1);
/* each of these falls through if not handled... */ /* each of these falls through if not handled... */
WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, 0, 0);

@ -55,7 +55,21 @@
#include "UI_view2d.h" #include "UI_view2d.h"
#include "node_intern.h" #include "node_intern.h"
/* ****** helpers ****** */
static bNode *node_under_mouse(bNodeTree *ntree, int mx, int my)
{
bNode *node;
for(next_node(ntree); (node=next_node(NULL));) {
/* node body (header and scale are in other operators) */
if (BLI_in_rctf(&node->totr, mx, my))
return node;
}
return NULL;
}
/* ****** Click Select ****** */ /* ****** Click Select ****** */
static bNode *node_mouse_select(SpaceNode *snode, ARegion *ar, short *mval, short extend) static bNode *node_mouse_select(SpaceNode *snode, ARegion *ar, short *mval, short extend)
@ -70,11 +84,7 @@ static bNode *node_mouse_select(SpaceNode *snode, ARegion *ar, short *mval, shor
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my); UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my);
/* find the closest visible node */ /* find the closest visible node */
for(next_node(snode->edittree); (node=next_node(NULL));) { node = node_under_mouse(snode->edittree, mx, my);
/* node body (header and scale are in other operators) */
if (BLI_in_rctf(&node->totr, mx, my))
break;
}
if (node) { if (node) {
if (extend == 0) { if (extend == 0) {
@ -177,9 +187,6 @@ static int node_borderselect_exec(bContext *C, wmOperator *op)
rect.ymax= RNA_int_get(op->ptr, "ymax"); rect.ymax= RNA_int_get(op->ptr, "ymax");
UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax); UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
if (snode->edittree == NULL) // XXX should this be in poll()? - campbell
return OPERATOR_FINISHED;
for(node= snode->edittree->nodes.first; node; node= node->next) { for(node= snode->edittree->nodes.first; node; node= node->next) {
if(BLI_isect_rctf(&rectf, &node->totr, NULL)) { if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
if(gesture_mode==GESTURE_MODAL_SELECT) if(gesture_mode==GESTURE_MODAL_SELECT)
@ -194,6 +201,34 @@ static int node_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED; return OPERATOR_FINISHED;
} }
static int node_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
int tweak = RNA_boolean_get(op->ptr, "tweak");
if (tweak) {
/* prevent initiating the border select if the mouse is over a node */
/* this allows border select on empty space, but drag-translate on nodes */
SpaceNode *snode= CTX_wm_space_node(C);
ARegion *ar= CTX_wm_region(C);
short mval[2];
float mx, my;
mval[0]= event->x - ar->winrct.xmin;
mval[1]= event->y - ar->winrct.ymin;
/* get mouse coordinates in view2d space */
mx= (float)mval[0];
my= (float)mval[1];
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my);
if (node_under_mouse(snode->edittree, mx, my))
return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
}
return WM_border_select_invoke(C, op, event);
}
void NODE_OT_select_border(wmOperatorType *ot) void NODE_OT_select_border(wmOperatorType *ot)
{ {
/* identifiers */ /* identifiers */
@ -201,7 +236,7 @@ void NODE_OT_select_border(wmOperatorType *ot)
ot->idname= "NODE_OT_select_border"; ot->idname= "NODE_OT_select_border";
/* api callbacks */ /* api callbacks */
ot->invoke= WM_border_select_invoke; ot->invoke= node_border_select_invoke;
ot->exec= node_borderselect_exec; ot->exec= node_borderselect_exec;
ot->modal= WM_border_select_modal; ot->modal= WM_border_select_modal;
@ -212,6 +247,7 @@ void NODE_OT_select_border(wmOperatorType *ot)
/* rna */ /* rna */
WM_operator_properties_gesture_border(ot, FALSE); WM_operator_properties_gesture_border(ot, FALSE);
RNA_def_boolean(ot->srna, "tweak", 0, "Tweak", "Only activate when mouse is not over a node - useful for tweak gesture");
} }
/* ****** Select/Deselect All ****** */ /* ****** Select/Deselect All ****** */

@ -95,8 +95,6 @@ typedef struct bNodeSocket {
#define SOCK_IN_USE 4 #define SOCK_IN_USE 4
/* unavailable is for dynamic sockets */ /* unavailable is for dynamic sockets */
#define SOCK_UNAVAIL 8 #define SOCK_UNAVAIL 8
/* flag for selection status */
#define SOCK_SEL 16
# #
# #
typedef struct bNodePreview { typedef struct bNodePreview {
@ -185,10 +183,8 @@ typedef struct bNodeTree {
ListBase alltypes; /* type definitions */ ListBase alltypes; /* type definitions */
struct bNodeType *owntype; /* for groups or dynamic trees, no read/write */ struct bNodeType *owntype; /* for groups or dynamic trees, no read/write */
/* selected input/output socket */ int pad2[2];
bNodeSocket *selin;
bNodeSocket *selout;
/* callbacks */ /* callbacks */
void (*timecursor)(void *, int nr); void (*timecursor)(void *, int nr);
void (*stats_draw)(void *, char *str); void (*stats_draw)(void *, char *str);