Extended modes for snapping in the node editor.
authorLukas Toenne <lukas.toenne@googlemail.com>
Fri, 29 Jun 2012 14:34:46 +0000 (14:34 +0000)
committerLukas Toenne <lukas.toenne@googlemail.com>
Fri, 29 Jun 2012 14:34:46 +0000 (14:34 +0000)
The transform operators in nodes will now use the unselected nodes to generate snapping points. Unlike object snapping, node snapping works for the x/y axes separately and snaps node borders to same borders of unselected nodes. The sensitive area for node borders extends over the whole view2D range, to enable simple alignment of nodes in both x and y direction.

For snap points in the node editor an additional enum value is stored to indicate the type of node border (left/right/top/bottom). This works as a constraint on possible node alignments: only same border types align with each other.

13 files changed:
release/scripts/startup/bl_ui/space_node.py
source/blender/editors/include/ED_node.h
source/blender/editors/include/ED_transform.h
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_draw.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_constraints.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_snap.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/rna_scene.c

index d7f25a597eddd5fa2ce60787976ae3f6d8f7802d..bb29e415c1955e07b72b3176d1a709a96e39dc5c 100644 (file)
@@ -90,6 +90,9 @@ class NODE_HT_header(Header):
         # Snap
         row = layout.row(align=True)
         row.prop(toolsettings, "use_snap", text="")
+        row.prop(toolsettings, "snap_node_element", text="", icon_only=True)
+        if toolsettings.snap_node_element != 'INCREMENT':
+            row.prop(toolsettings, "snap_target", text="")
 
         layout.template_running_jobs()
 
index 0979e3ec92b14ab4a7e3a36ed6db210fe8ed2867..6f86d01fb98a8e7eb265b3e7a50eecbc3922a668 100644 (file)
@@ -41,10 +41,20 @@ struct bNodeTree;
 struct bNode;
 struct bNodeTree;
 struct ScrArea;
+struct View2D;
+
+typedef enum {
+       NODE_TOP    = 1,
+       NODE_BOTTOM = 2,
+       NODE_LEFT   = 4,
+       NODE_RIGHT  = 8
+} NodeBorder;
 
 /* drawnode.c */
 void ED_init_node_butfuncs(void);
 
+void drawnodesnap(struct View2D *v2d, const float cent[2], float size, NodeBorder border);
+
 /* node_draw.c */
 void ED_node_tree_update(struct SpaceNode *snode, struct Scene *scene);
 void ED_node_changed_update(struct ID *id, struct bNode *node);
index 608df8dd9b3026b4874d61d6045807b7330084a5..d7e9fc323a66da3882282aa9fce6defbef3cb250 100644 (file)
@@ -180,6 +180,8 @@ int peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, cons
 int peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
 int snapObjectsTransform(struct TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode);
 int snapObjectsContext(struct bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode);
+int snapNodesTransform(struct TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode);
+int snapNodesContext(struct bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode);
 
 #endif
 
index cc58c4174b3ca893a7c517fcf0d5cb8ad9316b5d..d644747413be7e7c70697d50691de680144a2368 100644 (file)
@@ -3351,3 +3351,28 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
        node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
 //     node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
 }
+
+void drawnodesnap(View2D *v2d, const float cent[2], float size, NodeBorder border)
+{
+       glBegin(GL_LINES);
+       
+       if (border & (NODE_LEFT | NODE_RIGHT)) {
+               glVertex2f(cent[0], v2d->cur.ymin);
+               glVertex2f(cent[0], v2d->cur.ymax);
+       }
+       else {
+               glVertex2f(cent[0], cent[1] - size);
+               glVertex2f(cent[0], cent[1] + size);
+       }
+       
+       if (border & (NODE_TOP | NODE_BOTTOM)) {
+               glVertex2f(v2d->cur.xmin, cent[1]);
+               glVertex2f(v2d->cur.xmax, cent[1]);
+       }
+       else {
+               glVertex2f(cent[0] - size, cent[1]);
+               glVertex2f(cent[0] + size, cent[1]);
+       }
+       
+       glEnd();
+}
index f9aa0dfd582aa9dd58cec6904942da7eca5d0faf..17d7530d2a7858aacdc47190e783982430a3f6da 100644 (file)
@@ -65,6 +65,7 @@
 
 #include "ED_node.h"
 #include "ED_gpencil.h"
+#include "ED_space_api.h"
 
 #include "UI_interface.h"
 #include "UI_interface_icons.h"
@@ -1087,6 +1088,8 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
        
        //uiFreeBlocksWin(&sa->uiblocks, sa->win);
 
+       ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
+
        /* only set once */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_MAP1_VERTEX_3);
@@ -1139,6 +1142,8 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
        glDisable(GL_LINE_SMOOTH);
        glDisable(GL_BLEND);
        
+       ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
+       
        /* draw grease-pencil ('canvas' strokes) */
        if (snode->nodetree)
                draw_gpencil_view2d(C, 1);
index a00376974a5a7fb74e0714089cc2fa3e02cbcc1e..1d70c6d68f2b1552699a6b2fd5d3b76b46dbb009 100644 (file)
@@ -1655,6 +1655,12 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
                unit_m3(t->spacemtx);
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
        }
+       else if (t->spacetype == SPACE_NODE) {
+               unit_m3(t->spacemtx);
+               /*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/
+               t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+               /*t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);*/
+       }
        else
                unit_m3(t->spacemtx);
 
index fdc09c1bed0cde90ad1086080d35e78f7fe65044..3ab5bf7bbfb226a3504208c2cce3449bc9b0f16a 100644 (file)
@@ -86,6 +86,7 @@ typedef struct TransSnap {
        float   snapTarget[3]; /* to this point */
        float   snapNormal[3];
        float   snapTangent[3];
+       char    snapNodeBorder;
        ListBase points;
        TransSnapPoint  *selectedPoint;
        float   dist; // Distance from snapPoint to snapTarget
index f4c025f71be28a02efbc7534f4e5436596c5d7c7..8ca29864dff608c70fbd8114fccc38095dbb761c 100644 (file)
@@ -640,7 +640,7 @@ void drawConstraint(TransInfo *t)
 {
        TransCon *tc = &(t->con);
 
-       if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE))
+       if (!ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE))
                return;
        if (!(tc->mode & CON_APPLY))
                return;
index f3a846daf29e04cfba97a6b9e6369b4601e6e663..af0b33d58aec1a34d4488ed272fe067d91cc0e61 100644 (file)
@@ -5516,8 +5516,11 @@ static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node)
        }
 
        td->loc = td2d->loc;
-       copy_v3_v3(td->center, td->loc);
        copy_v3_v3(td->iloc, td->loc);
+       /* use node center instead of origin (top-left corner) */
+       td->center[0] = node->locx + 0.5f * (node->totr.xmax - node->totr.xmin);
+       td->center[1] = node->locy - 0.5f * (node->totr.ymax - node->totr.ymin);        /* node height is used negative */
+       td->center[2] = 0.0f;
 
        memset(td->axismtx, 0, sizeof(td->axismtx));
        td->axismtx[2][2] = 1.0f;
@@ -5529,6 +5532,8 @@ static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node)
 
        unit_m3(td->mtx);
        unit_m3(td->smtx);
+
+       td->extra = node;
 }
 
 static void createTransNodeData(bContext *C, TransInfo *t)
@@ -6324,7 +6329,7 @@ void createTransData(bContext *C, TransInfo *t)
 #endif
        }
        else if (t->spacetype == SPACE_NODE) {
-               t->flag |= T_2D_EDIT | T_POINTS;
+               t->flag |= T_POINTS | T_2D_EDIT;
                createTransNodeData(C, t);
                if (t->data && (t->flag & T_PROP_EDIT)) {
                        sort_trans_data(t); // makes selected become first in array
index d485b886ea701f1fa11dba150b725256075e9d9d..c49e1715f34544aeb705105041db0b067fa5c6df 100644 (file)
@@ -42,6 +42,7 @@
 #include "DNA_object_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h" // Temporary, for snapping to other unselected meshes
+#include "DNA_node_types.h"
 #include "DNA_space_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_view3d_types.h"
@@ -74,6 +75,7 @@
 #include "ED_armature.h"
 #include "ED_image.h"
 #include "ED_mesh.h"
+#include "ED_node.h"
 #include "ED_uvedit.h"
 #include "ED_view3d.h"
 
@@ -113,6 +115,9 @@ static float ResizeBetween(TransInfo *t, float p1[3], float p2[3]);
 
 /****************** IMPLEMENTATIONS *********************/
 
+static int snapNodeTest(View2D *v2d, bNode *node, SnapMode mode);
+static NodeBorder snapNodeBorder(int snap_node_mode);
+
 #if 0
 int BIF_snappingSupported(Object *obedit)
 {
@@ -140,19 +145,22 @@ int activeSnap(TransInfo *t)
 
 void drawSnapping(const struct bContext *C, TransInfo *t)
 {
-       if (validSnap(t) && activeSnap(t)) {
-               
-               unsigned char col[4], selectedCol[4], activeCol[4];
-               UI_GetThemeColor3ubv(TH_TRANSFORM, col);
-               col[3] = 128;
-               
-               UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
-               selectedCol[3] = 128;
-
-               UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
-               activeCol[3] = 192;
-
-               if (t->spacetype == SPACE_VIEW3D) {
+       unsigned char col[4], selectedCol[4], activeCol[4];
+       
+       if (!activeSnap(t))
+               return;
+       
+       UI_GetThemeColor3ubv(TH_TRANSFORM, col);
+       col[3] = 128;
+       
+       UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
+       selectedCol[3] = 128;
+       
+       UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
+       activeCol[3] = 192;
+       
+       if (t->spacetype == SPACE_VIEW3D) {
+               if (validSnap(t)) {
                        TransSnapPoint *p;
                        View3D *v3d = CTX_wm_view3d(C);
                        RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -160,11 +168,11 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
                        float size;
                        
                        glDisable(GL_DEPTH_TEST);
-       
+                       
                        size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
-
+                       
                        invert_m4_m4(imat, rv3d->viewmat);
-
+                       
                        for (p = t->tsnap.points.first; p; p = p->next) {
                                if (p == t->tsnap.selectedPoint) {
                                        glColor4ubv(selectedCol);
@@ -172,20 +180,20 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
                                else {
                                        glColor4ubv(col);
                                }
-
+                               
                                drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat);
                        }
-
+                       
                        if (t->tsnap.status & POINT_INIT) {
                                glColor4ubv(activeCol);
-
+                               
                                drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat);
                        }
                        
                        /* draw normal if needed */
                        if (usingSnappingNormal(t) && validSnappingNormal(t)) {
                                glColor4ubv(activeCol);
-
+                               
                                glBegin(GL_LINES);
                                glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
                                glVertex3f(t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
@@ -197,7 +205,9 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
                        if (v3d->zbuf)
                                glEnable(GL_DEPTH_TEST);
                }
-               else if (t->spacetype == SPACE_IMAGE) {
+       }
+       else if (t->spacetype == SPACE_IMAGE) {
+               if (validSnap(t)) {
                        /* This will not draw, and Im nor sure why - campbell */
 #if 0
                        float xuser_asp, yuser_asp;
@@ -228,7 +238,36 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
                        glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
                        setlinestyle(0);
 #endif
+               }
+       }
+       else if (t->spacetype == SPACE_NODE) {
+               if (validSnap(t)) {
+                       ARegion *ar = CTX_wm_region(C);
+                       TransSnapPoint *p;
+                       float size;
+                       
+                       size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+                       
+                       glEnable(GL_BLEND);
                        
+                       for (p = t->tsnap.points.first; p; p = p->next) {
+                               if (p == t->tsnap.selectedPoint) {
+                                       glColor4ubv(selectedCol);
+                               }
+                               else {
+                                       glColor4ubv(col);
+                               }
+                               
+                               drawnodesnap(&ar->v2d, p->co, size, 0);
+                       }
+                       
+                       if (t->tsnap.status & POINT_INIT) {
+                               glColor4ubv(activeCol);
+                               
+                               drawnodesnap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder);
+                       }
+                       
+                       glDisable(GL_BLEND);
                }
        }
 }
@@ -349,6 +388,8 @@ void resetSnapping(TransInfo *t)
        t->tsnap.snapNormal[0] = 0;
        t->tsnap.snapNormal[1] = 0;
        t->tsnap.snapNormal[2] = 0;
+       
+       t->tsnap.snapNodeBorder = 0;
 }
 
 int usingSnappingNormal(TransInfo *t)
@@ -373,12 +414,20 @@ static void initSnappingMode(TransInfo *t)
        Object *obedit = t->obedit;
        Scene *scene = t->scene;
 
-       /* force project off when not supported */
-       if (ts->snap_mode != SCE_SNAP_MODE_FACE) {
+       if (t->spacetype == SPACE_NODE) {
+               /* force project off when not supported */
                t->tsnap.project = 0;
+               
+               t->tsnap.mode = ts->snap_node_mode;
+       }
+       else {
+               /* force project off when not supported */
+               if (ts->snap_mode != SCE_SNAP_MODE_FACE) {
+                       t->tsnap.project = 0;
+               }
+               
+               t->tsnap.mode = ts->snap_mode;
        }
-
-       t->tsnap.mode = ts->snap_mode;
 
        if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) &&  /* Only 3D view or UV */
            (t->flag & T_CAMERA) == 0)  /* Not with camera selected in camera view */
@@ -414,6 +463,19 @@ static void initSnappingMode(TransInfo *t)
                        t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
                }
        }
+       else if (t->spacetype == SPACE_NODE)
+       {
+               setSnappingCallback(t);
+               
+               if (t->tsnap.applySnap != NULL)
+               {
+                       t->tsnap.modeSelect = SNAP_NOT_SELECTED;
+               }
+               else {
+                       /* Grid if snap is not possible */
+                       t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
+               }
+       }
        else {
                /* Always grid outside of 3D view */
                t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
@@ -624,7 +686,17 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
 {
        float point[3];
        getSnapPoint(t, point);
-       sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
+
+       if (t->spacetype == SPACE_NODE) {
+               char border = t->tsnap.snapNodeBorder;
+               if (border & (NODE_LEFT | NODE_RIGHT))
+                       vec[0] = point[0] - t->tsnap.snapTarget[0];
+               if (border & (NODE_BOTTOM | NODE_TOP))
+                       vec[1] = point[1] - t->tsnap.snapTarget[1];
+       }
+       else {
+               sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
+       }
 }
 
 static void ApplySnapRotation(TransInfo *t, float *value)
@@ -879,20 +951,57 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
                        t->tsnap.status &= ~POINT_INIT;
                }
        }
+       else if (t->spacetype == SPACE_NODE) {
+               float loc[2];
+               int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
+               char node_border;
+               
+               if (snapNodesTransform(t, t->mval, &dist, loc, &node_border, t->tsnap.modeSelect)) {
+                       copy_v2_v2(t->tsnap.snapPoint, loc);
+                       t->tsnap.snapNodeBorder = node_border;
+                       
+                       t->tsnap.status |=  POINT_INIT;
+               }
+               else {
+                       t->tsnap.status &= ~POINT_INIT;
+               }
+       }
 }
 
 /********************** TARGET **************************/
 
+static void TargetSnapOffset(TransInfo *t, TransData *td)
+{
+       if (t->spacetype == SPACE_NODE && td != NULL) {
+               bNode *node = td->extra;
+               char border = t->tsnap.snapNodeBorder;
+               float width = node->totr.xmax - node->totr.xmin;
+               float height = node->totr.ymax - node->totr.ymin;
+               
+               if (border & NODE_LEFT)
+                       t->tsnap.snapTarget[0] -= 0.5f * width;
+               if (border & NODE_RIGHT)
+                       t->tsnap.snapTarget[0] += 0.5f * width;
+               if (border & NODE_BOTTOM)
+                       t->tsnap.snapTarget[1] -= 0.5f * height;
+               if (border & NODE_TOP)
+                       t->tsnap.snapTarget[1] += 0.5f * height;
+       }
+}
+
 static void TargetSnapCenter(TransInfo *t)
 {
        /* Only need to calculate once */
        if ((t->tsnap.status & TARGET_INIT) == 0) {
                copy_v3_v3(t->tsnap.snapTarget, t->center);     
+               
                if (t->flag & (T_EDIT | T_POSE)) {
                        Object *ob = t->obedit ? t->obedit : t->poseobj;
                        mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
                }
                
+               TargetSnapOffset(t, NULL);
+               
                t->tsnap.status |= TARGET_INIT;         
        }
 }
@@ -914,12 +1023,14 @@ static void TargetSnapActive(TransInfo *t)
 
                if (active_td) {
                        copy_v3_v3(t->tsnap.snapTarget, active_td->center);
-                               
+                       
                        if (t->flag & (T_EDIT | T_POSE)) {
                                Object *ob = t->obedit ? t->obedit : t->poseobj;
                                mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
                        }
                        
+                       TargetSnapOffset(t, active_td);
+                       
                        t->tsnap.status |= TARGET_INIT;
                }
                /* No active, default to median */
@@ -953,6 +1064,8 @@ static void TargetSnapMedian(TransInfo *t)
                        mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
                }
                
+               TargetSnapOffset(t, NULL);
+               
                t->tsnap.status |= TARGET_INIT;         
        }
 }
@@ -1029,6 +1142,8 @@ static void TargetSnapClosest(TransInfo *t)
                        }
                }
                
+               TargetSnapOffset(t, closest);
+               
                t->tsnap.status |= TARGET_INIT;
        }
 }
@@ -1876,6 +1991,113 @@ int peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2],
        return peelObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), depth_peels, mval, mode);
 }
 
+/******************** NODES ***********************************/
+
+static int snapNodeTest(View2D *v2d, bNode *node, SnapMode mode)
+{
+       /* node is use for snapping only if a) snap mode matches and b) node is inside the view */
+       return ((mode == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
+               (mode == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
+               (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
+                node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
+}
+
+static NodeBorder snapNodeBorder(int snap_node_mode)
+{
+       switch (snap_node_mode) {
+               case SCE_SNAP_MODE_NODE_X:
+                       return NODE_LEFT | NODE_RIGHT;
+               case SCE_SNAP_MODE_NODE_Y:
+                       return NODE_TOP | NODE_BOTTOM;
+               case SCE_SNAP_MODE_NODE_XY:
+                       return NODE_LEFT | NODE_RIGHT | NODE_TOP | NODE_BOTTOM;
+       }
+       return 0;
+}
+
+static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2],
+                    float r_loc[2], int *r_dist, char *r_node_border)
+{
+       View2D *v2d = &ar->v2d;
+       NodeBorder border = snapNodeBorder(ts->snap_node_mode);
+       int retval = 0;
+       rcti totr;
+       int new_dist;
+       
+       UI_view2d_to_region_no_clip(v2d, node->totr.xmin, node->totr.ymin, &totr.xmin, &totr.ymin);
+       UI_view2d_to_region_no_clip(v2d, node->totr.xmax, node->totr.ymax, &totr.xmax, &totr.ymax);
+       
+       if (border & NODE_LEFT) {
+               new_dist = abs(totr.xmin - mval[0]);
+               if (new_dist < *r_dist) {
+                       UI_view2d_region_to_view(v2d, totr.xmin, mval[1], &r_loc[0], &r_loc[1]);
+                       *r_dist = new_dist;
+                       *r_node_border = NODE_LEFT;
+                       retval = 1;
+               }
+       }
+       
+       if (border & NODE_RIGHT) {
+               new_dist = abs(totr.xmax - mval[0]);
+               if (new_dist < *r_dist) {
+                       UI_view2d_region_to_view(v2d, totr.xmax, mval[1], &r_loc[0], &r_loc[1]);
+                       *r_dist = new_dist;
+                       *r_node_border = NODE_RIGHT;
+                       retval = 1;
+               }
+       }
+       
+       if (border & NODE_BOTTOM) {
+               new_dist = abs(totr.ymin - mval[1]);
+               if (new_dist < *r_dist) {
+                       UI_view2d_region_to_view(v2d, mval[0], totr.ymin, &r_loc[0], &r_loc[1]);
+                       *r_dist = new_dist;
+                       *r_node_border = NODE_BOTTOM;
+                       retval = 1;
+               }
+       }
+       
+       if (border & NODE_TOP) {
+               new_dist = abs(totr.ymax - mval[1]);
+               if (new_dist < *r_dist) {
+                       UI_view2d_region_to_view(v2d, mval[0], totr.ymax, &r_loc[0], &r_loc[1]);
+                       *r_dist = new_dist;
+                       *r_node_border = NODE_TOP;
+                       retval = 1;
+               }
+       }
+       
+       return retval;
+}
+
+static int snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2],
+                     int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
+{
+       bNodeTree *ntree = snode->edittree;
+       bNode *node;
+       int retval = 0;
+       
+       *r_node_border = 0;
+       
+       for (node = ntree->nodes.first; node; node = node->next) {
+               if (snapNodeTest(&ar->v2d, node, mode))
+                       retval |= snapNode(ts, snode, ar, node, mval, r_loc, r_dist, r_node_border);
+       }
+       
+       return retval;
+}
+
+int snapNodesTransform(TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
+{
+       return snapNodes(t->settings, t->sa->spacedata.first, t->ar, mval, r_dist, r_loc, r_node_border, mode);
+}
+
+int snapNodesContext(bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode)
+{
+       Scene *scene = CTX_data_scene(C);
+       return snapNodes(scene->toolsettings, CTX_wm_space_node(C), CTX_wm_region(C), mval, r_dist, r_loc, r_node_border, mode);
+}
+
 /*================================================================*/
 
 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
index 6a8022c07a5cafec635fe356b3cc87baa4976c95..02a7d0da3258bf0727809a0943a42e73528489b9 100644 (file)
@@ -899,7 +899,7 @@ typedef struct ToolSettings {
 
        /* Subdivide Settings */
        short cornertype;
-       short pad3;
+       short pad1;
        /*Triangle to Quad conversion threshold*/
        float jointrilimit;
        /* Editmode Tools */
@@ -995,12 +995,13 @@ typedef struct ToolSettings {
        char edge_mode_live_unwrap;
 
        /* Transform */
-       char snap_mode;
+       char snap_mode, snap_node_mode;
+       char pad3;
        short snap_flag, snap_target;
        short proportional, prop_mode;
        char proportional_objects; /* proportional edit, object mode */
        char proportional_mask; /* proportional edit, object mode */
-       char pad[4];
+       char pad4[2];
 
        char auto_normalize; /*auto normalizing mode in wpaint*/
        char multipaint; /* paint multiple bones in wpaint */
@@ -1012,7 +1013,7 @@ typedef struct ToolSettings {
        int uv_relax_method;
        /* XXX: these sculpt_paint_* fields are deprecated, use the
         * unified_paint_settings field instead! */
-       short sculpt_paint_settings DNA_DEPRECATED;     short pad1;
+       short sculpt_paint_settings DNA_DEPRECATED;     short pad5;
        int sculpt_paint_unified_size DNA_DEPRECATED;
        float sculpt_paint_unified_unprojected_radius DNA_DEPRECATED;
        float sculpt_paint_unified_alpha DNA_DEPRECATED;
@@ -1370,6 +1371,9 @@ typedef struct Scene {
 #define SCE_SNAP_MODE_EDGE             2
 #define SCE_SNAP_MODE_FACE             3
 #define SCE_SNAP_MODE_VOLUME   4
+#define SCE_SNAP_MODE_NODE_X   5
+#define SCE_SNAP_MODE_NODE_Y   6
+#define SCE_SNAP_MODE_NODE_XY  7
 
 /* toolsettings->selectmode */
 #define SCE_SELECT_VERTEX      1 /* for mesh */
index a8d176db7679c4893b9c70f1e0f545d588cb4c75..a0614a9d82a7cfef0118b27e8cfe9b2daa121c4b 100644 (file)
@@ -45,6 +45,7 @@ extern EnumPropertyItem proportional_falloff_curve_only_items[];
 extern EnumPropertyItem proportional_editing_items[];
 extern EnumPropertyItem snap_target_items[];
 extern EnumPropertyItem snap_element_items[];
+extern EnumPropertyItem snap_node_element_items[];
 extern EnumPropertyItem mesh_select_mode_items[];
 extern EnumPropertyItem space_type_items[];
 extern EnumPropertyItem region_type_items[];
index 7a2f0736e983f6bf24173d87ceb70108342683cc..4c0d6eb30d2031dd24faa886ff79c293cbba7d95 100644 (file)
@@ -136,6 +136,14 @@ EnumPropertyItem snap_element_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+EnumPropertyItem snap_node_element_items[] = {
+       {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
+       {SCE_SNAP_MODE_NODE_X, "NODE_X", ICON_SNAP_EDGE, "Node X", "Snap to left/right node border"},
+       {SCE_SNAP_MODE_NODE_Y, "NODE_Y", ICON_SNAP_EDGE, "Node Y", "Snap to top/bottom node border"},
+       {SCE_SNAP_MODE_NODE_XY, "NODE_XY", ICON_SNAP_EDGE, "Node X / Y", "Snap to any node border"},
+       {0, NULL, 0, NULL, NULL}
+};
+
 
 /* workaround for duplice enums,
  * have each enum line as a defne then conditionally set it or not
@@ -1626,6 +1634,13 @@ static void rna_def_tool_settings(BlenderRNA  *brna)
        RNA_def_property_enum_items(prop, snap_element_items);
        RNA_def_property_ui_text(prop, "Snap Element", "Type of element to snap to");
        RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+       
+       /* node editor uses own set of snap modes */
+       prop = RNA_def_property(srna, "snap_node_element", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "snap_node_mode");
+       RNA_def_property_enum_items(prop, snap_node_element_items);
+       RNA_def_property_ui_text(prop, "Snap Node Element", "Type of element to snap to");
+       RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
 
        prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "snap_target");
@@ -1651,7 +1666,7 @@ static void rna_def_tool_settings(BlenderRNA  *brna)
        RNA_def_property_ui_text(prop, "Project to Self", "Snap onto itself (editmode)");
        RNA_def_property_ui_icon(prop, ICON_ORTHO, 0);
        RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
-       
+
        /* Grease Pencil */
        prop = RNA_def_property(srna, "use_grease_pencil_sessions", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINTSESSIONS_ON);