Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Toenne <lukas.toenne@googlemail.com>2012-06-29 18:34:46 +0400
committerLukas Toenne <lukas.toenne@googlemail.com>2012-06-29 18:34:46 +0400
commit83093d677049f6ba085c34d1719906e2ee3cc3d1 (patch)
tree22c356af6a5657cd8bf1b37ddb3ca5503a243d73 /source/blender
parent344ca17247accd2848081e69eab00ab7aac4a0ae (diff)
Extended modes for snapping in the node editor.
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.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/include/ED_node.h10
-rw-r--r--source/blender/editors/include/ED_transform.h2
-rw-r--r--source/blender/editors/space_node/drawnode.c25
-rw-r--r--source/blender/editors/space_node/node_draw.c5
-rw-r--r--source/blender/editors/transform/transform.c6
-rw-r--r--source/blender/editors/transform/transform.h1
-rw-r--r--source/blender/editors/transform/transform_constraints.c2
-rw-r--r--source/blender/editors/transform/transform_conversions.c9
-rw-r--r--source/blender/editors/transform/transform_snap.c276
-rw-r--r--source/blender/makesdna/DNA_scene_types.h12
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c17
12 files changed, 331 insertions, 35 deletions
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 0979e3ec92b..6f86d01fb98 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -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);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 608df8dd9b3..d7e9fc323a6 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -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
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index cc58c4174b3..d644747413b 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -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();
+}
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index f9aa0dfd582..17d7530d2a7 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -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);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a00376974a5..1d70c6d68f2 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -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);
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index fdc09c1bed0..3ab5bf7bbfb 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -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
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index f4c025f71be..8ca29864dff 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -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;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index f3a846daf29..af0b33d58ae 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -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
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index d485b886ea7..c49e1715f34 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -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);
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 6a8022c07a5..02a7d0da325 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -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 */
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index a8d176db767..a0614a9d82a 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -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[];
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 7a2f0736e98..4c0d6eb30d2 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -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);