diff --git a/node_efficiency_tools.py b/node_efficiency_tools.py
index 3f2aeeb3eb09eb63a4a7d7d3be469bfda5b0b347..9d53e77985ff696e6fca17eef7741974c9616d4b 100644
--- a/node_efficiency_tools.py
+++ b/node_efficiency_tools.py
@@ -19,7 +19,7 @@
 bl_info = {
     'name': "Node Wrangler (aka Nodes Efficiency Tools)",
     'author': "Bartek Skorupa, Greg Zaal",
-    'version': (3, 1),
+    'version': (3, 2),
     'blender': (2, 69, 0),
     'location': "Node Editor Properties Panel  or  Ctrl-SPACE",
     'description': "Various tools to enhance and speed up node-based workflow",
@@ -32,7 +32,7 @@ bl_info = {
 
 import bpy, blf, bgl
 from bpy.types import Operator, Panel, Menu
-from bpy.props import FloatProperty, EnumProperty, BoolProperty, StringProperty, FloatVectorProperty
+from bpy.props import FloatProperty, EnumProperty, BoolProperty, IntProperty, StringProperty, FloatVectorProperty
 from mathutils import Vector
 from math import cos, sin, pi, sqrt
 
@@ -459,6 +459,10 @@ def hack_force_update(context, nodes):
     return False
 
 
+def dpifac():
+    return bpy.context.user_preferences.system.dpi/72
+
+
 def is_end_node(node):
     bool = True
     for output in node.outputs:
@@ -480,6 +484,14 @@ def node_mid_pt(node, axis):
 
 def autolink(node1, node2, links):
     link_made = False
+
+    for outp in node1.outputs:
+        for inp in node2.inputs:
+            if not inp.is_linked and inp.name == outp.name:
+                link_made = True
+                links.new(outp, inp)
+                return True
+
     for outp in node1.outputs:
         for inp in node2.inputs:
             if not inp.is_linked and inp.type == outp.type:
@@ -521,22 +533,47 @@ def node_at_pos(nodes, context, event):
 
     store_mouse_cursor(context, event)
     x, y = context.space_data.cursor_location
+    x = x
+    y = y
+
+    # Make a list of each corner (and middle of border) for each node.
+    # Will be sorted to find nearest point and thus nearest node
+    node_points_with_dist = []
+    for node in nodes:
+        locx = node.location.x
+        locy = node.location.y
+        dimx = node.dimensions.x/dpifac()
+        dimy = node.dimensions.y/dpifac()
+        node_points_with_dist.append([node, sqrt((x - locx) ** 2 + (y - locy) ** 2)])  # Top Left
+        node_points_with_dist.append([node, sqrt((x - (locx+dimx)) ** 2 + (y - locy) ** 2)])  # Top Right
+        node_points_with_dist.append([node, sqrt((x - locx) ** 2 + (y - (locy-dimy)) ** 2)])  # Bottom Left
+        node_points_with_dist.append([node, sqrt((x - (locx+dimx)) ** 2 + (y - (locy-dimy)) ** 2)])  # Bottom Right
+
+        node_points_with_dist.append([node, sqrt((x - (locx+(dimx/2))) ** 2 + (y - locy) ** 2)])  # Mid Top
+        node_points_with_dist.append([node, sqrt((x - (locx+(dimx/2))) ** 2 + (y - (locy-dimy)) ** 2)])  # Mid Bottom
+        node_points_with_dist.append([node, sqrt((x - locx) ** 2 + (y - (locy-(dimy/2))) ** 2)])  # Mid Left
+        node_points_with_dist.append([node, sqrt((x - (locx+dimx)) ** 2 + (y - (locy-(dimy/2))) ** 2)])  # Mid Right
+
+        #node_points_with_dist.append([node, sqrt((x - (locx+(dimx/2))) ** 2 + (y - (locy-(dimy/2))) ** 2)])  # Center
 
-    # nearest node
-    nodes_near_mouse = sorted(nodes, key=lambda k: sqrt((x - node_mid_pt(k, 'x')) ** 2 + (y - node_mid_pt(k, 'y')) ** 2))
+    nearest_node = sorted(node_points_with_dist, key=lambda k: k[1])[0][0]
 
     for node in nodes:
-        if (node.location.x <= x <= node.location.x + node.dimensions.x) and \
-           (node.location.y - node.dimensions.y <= y <= node.location.y):
+        locx = node.location.x
+        locy = node.location.y
+        dimx = node.dimensions.x/dpifac()
+        dimy = node.dimensions.y/dpifac()
+        if (locx <= x <= locx + dimx) and \
+           (locy - dimy <= y <= locy):
             nodes_under_mouse.append(node)
 
     if len(nodes_under_mouse) == 1:
-        if nodes_under_mouse[0] != nodes_near_mouse[0]:
+        if nodes_under_mouse[0] != nearest_node:
             target_node = nodes_under_mouse[0]  # use the node under the mouse if there is one and only one
         else:
-            target_node = nodes_near_mouse[0]  # else use the nearest node
+            target_node = nearest_node  # else use the nearest node
     else:
-        target_node = nodes_near_mouse[0]
+        target_node = nearest_node
     return target_node
 
 
@@ -554,16 +591,19 @@ def store_mouse_cursor(context, event):
 
 def draw_line(x1, y1, x2, y2, size, colour=[1.0, 1.0, 1.0, 0.7]):
     bgl.glEnable(bgl.GL_BLEND)
-    bgl.glColor4f(colour[0], colour[1], colour[2], colour[3])
     bgl.glLineWidth(size)
+    bgl.glShadeModel(bgl.GL_SMOOTH)
 
     bgl.glBegin(bgl.GL_LINE_STRIP)
     try:
+        bgl.glColor4f(colour[0]+(1.0-colour[0])/4, colour[1]+(1.0-colour[1])/4, colour[2]+(1.0-colour[2])/4, colour[3]+(1.0-colour[3])/4)
         bgl.glVertex2f(x1, y1)
+        bgl.glColor4f(colour[0], colour[1], colour[2], colour[3])
         bgl.glVertex2f(x2, y2)
     except:
         pass
     bgl.glEnd()
+    bgl.glShadeModel(bgl.GL_FLAT)
 
 
 def draw_circle(mx, my, radius, colour=[1.0, 1.0, 1.0, 0.7]):
@@ -578,41 +618,152 @@ def draw_circle(mx, my, radius, colour=[1.0, 1.0, 1.0, 0.7]):
     bgl.glEnd()
 
 
-def draw_callback_mixnodes(self, context, mode="MIX"):
+def draw_rounded_node_border(node, radius=8, colour=[1.0, 1.0, 1.0, 0.7]):
+    bgl.glEnable(bgl.GL_BLEND)
+    settings = bpy.context.user_preferences.addons[__name__].preferences
+    if settings.bgl_antialiasing:
+        bgl.glEnable(bgl.GL_LINE_SMOOTH)
+    sides = 16
+    bgl.glColor4f(colour[0], colour[1], colour[2], colour[3])
+
+    nlocx = (node.location.x+1)*dpifac()
+    nlocy = (node.location.y+1)*dpifac()
+    ndimx = node.dimensions.x
+    ndimy = node.dimensions.y
+
+    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+    mx, my = bpy.context.region.view2d.view_to_region(nlocx, nlocy)
+    bgl.glVertex2f(mx,my)
+    for i in range(sides+1):
+        if (4<=i<=8):
+            if mx != 12000 and my != 12000:  # nodes that go over the view border give 12000 as coords
+                cosine = radius * cos(i * 2 * pi / sides) + mx
+                sine = radius * sin(i * 2 * pi / sides) + my
+                bgl.glVertex2f(cosine, sine)
+    bgl.glEnd()
+
+    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+    mx, my = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy)
+    bgl.glVertex2f(mx,my)
+    for i in range(sides+1):
+        if (0<=i<=4):
+            if mx != 12000 and my != 12000:
+                cosine = radius * cos(i * 2 * pi / sides) + mx
+                sine = radius * sin(i * 2 * pi / sides) + my
+                bgl.glVertex2f(cosine, sine)
+
+    bgl.glEnd()
+    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+    mx, my = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy)
+    bgl.glVertex2f(mx,my)
+    for i in range(sides+1):
+        if (8<=i<=12):
+            if mx != 12000 and my != 12000:
+                cosine = radius * cos(i * 2 * pi / sides) + mx
+                sine = radius * sin(i * 2 * pi / sides) + my
+                bgl.glVertex2f(cosine, sine)
+    bgl.glEnd()
+
+    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+    mx, my = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy)
+    bgl.glVertex2f(mx,my)
+    for i in range(sides+1):
+        if (12<=i<=16):
+            if mx != 12000 and my != 12000:
+                cosine = radius * cos(i * 2 * pi / sides) + mx
+                sine = radius * sin(i * 2 * pi / sides) + my
+                bgl.glVertex2f(cosine, sine)
+    bgl.glEnd()
+
+
+    bgl.glBegin(bgl.GL_QUADS)
+    m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy)
+    m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx, nlocy - ndimy)
+    if m1x != 12000 and m1y != 12000 and m2x != 12000 and m2y != 12000:
+        bgl.glVertex2f(m2x-radius,m2y)  # draw order is important, start with bottom left and go anti-clockwise
+        bgl.glVertex2f(m2x,m2y)
+        bgl.glVertex2f(m1x,m1y)
+        bgl.glVertex2f(m1x-radius,m1y)
+    bgl.glEnd()
+
+    bgl.glBegin(bgl.GL_QUADS)
+    m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy)
+    m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy)
+    if m1x != 12000 and m1y != 12000 and m2x != 12000 and m2y != 12000:
+        bgl.glVertex2f(m1x,m2y)  # draw order is important, start with bottom left and go anti-clockwise
+        bgl.glVertex2f(m2x,m2y)
+        bgl.glVertex2f(m2x,m1y+radius)
+        bgl.glVertex2f(m1x,m1y+radius)
+    bgl.glEnd()
+
+    bgl.glBegin(bgl.GL_QUADS)
+    m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy)
+    m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy - ndimy)
+    if m1x != 12000 and m1y != 12000 and m2x != 12000 and m2y != 12000:
+        bgl.glVertex2f(m2x,m2y)  # draw order is important, start with bottom left and go anti-clockwise
+        bgl.glVertex2f(m2x+radius,m2y)
+        bgl.glVertex2f(m1x+radius,m1y)
+        bgl.glVertex2f(m1x,m1y)
+    bgl.glEnd()
+
+    bgl.glBegin(bgl.GL_QUADS)
+    m1x, m1y = bpy.context.region.view2d.view_to_region(nlocx, nlocy-ndimy)
+    m2x, m2y = bpy.context.region.view2d.view_to_region(nlocx + ndimx, nlocy-ndimy)
+    if m1x != 12000 and m1y != 12000 and m2x != 12000 and m2y != 12000:
+        bgl.glVertex2f(m1x,m2y)  # draw order is important, start with bottom left and go anti-clockwise
+        bgl.glVertex2f(m2x,m2y)
+        bgl.glVertex2f(m2x,m1y-radius)
+        bgl.glVertex2f(m1x,m1y-radius)
+    bgl.glEnd()
+
+    bgl.glDisable(bgl.GL_BLEND)
+    if settings.bgl_antialiasing:
+        bgl.glDisable(bgl.GL_LINE_SMOOTH)
+
+
+def draw_callback_mixnodes(self, context, mode):
     if self.mouse_path:
+        nodes = context.space_data.node_tree.nodes
         settings = context.user_preferences.addons[__name__].preferences
         if settings.bgl_antialiasing:
             bgl.glEnable(bgl.GL_LINE_SMOOTH)
 
-        colors = []
-        if mode == 'MIX':
-            colors = draw_color_sets['red_white']
-        elif mode == 'RGBA':
-            colors = draw_color_sets['yellow']
-        elif mode == 'VECTOR':
-            colors = draw_color_sets['purple']
-        elif mode == 'VALUE':
-            colors = draw_color_sets['grey']
-        elif mode == 'SHADER':
-            colors = draw_color_sets['green']
-        else:
-            colors = draw_color_sets['black']
+        if mode == "LINK":
+            col_outer = [1.0, 0.2, 0.2, 0.4]
+            col_inner = [0.0, 0.0, 0.0, 0.5]
+            col_circle_inner = [0.3, 0.05, 0.05, 1.0]
+        if mode == "LINKMENU":
+            col_outer = [0.4, 0.6, 1.0, 0.4]
+            col_inner = [0.0, 0.0, 0.0, 0.5]
+            col_circle_inner = [0.08, 0.15, .3, 1.0]
+        elif mode == "MIX":
+            col_outer = [0.2, 1.0, 0.2, 0.4]
+            col_inner = [0.0, 0.0, 0.0, 0.5]
+            col_circle_inner = [0.05, 0.3, 0.05, 1.0]
 
         m1x = self.mouse_path[0][0]
         m1y = self.mouse_path[0][1]
         m2x = self.mouse_path[-1][0]
         m2y = self.mouse_path[-1][1]
 
-        # circle outline
-        draw_circle(m1x, m1y, 6, colors[0])
-        draw_circle(m2x, m2y, 6, colors[0])
+        n1 = nodes[context.scene.NWLazySource]
+        n2 = nodes[context.scene.NWLazyTarget]
 
-        draw_line(m1x, m1y, m2x, m2y, 4, colors[0])  # line outline
-        draw_line(m1x, m1y, m2x, m2y, 2, colors[1])  # line inner
+        draw_rounded_node_border(n1, radius=6, colour=col_outer)  # outline
+        draw_rounded_node_border(n1, radius=5, colour=col_inner)  # inner
+        draw_rounded_node_border(n2, radius=6, colour=col_outer)  # outline
+        draw_rounded_node_border(n2, radius=5, colour=col_inner)  # inner
+
+        draw_line(m1x, m1y, m2x, m2y, 4, col_outer)  # line outline
+        draw_line(m1x, m1y, m2x, m2y, 2, col_inner)  # line inner
+
+        # circle outline
+        draw_circle(m1x, m1y, 6, col_outer)
+        draw_circle(m2x, m2y, 6, col_outer)
 
         # circle inner
-        draw_circle(m1x, m1y, 5, colors[2])
-        draw_circle(m2x, m2y, 5, colors[2])
+        draw_circle(m1x, m1y, 5, col_circle_inner)
+        draw_circle(m2x, m2y, 5, col_circle_inner)
 
         # restore opengl defaults
         bgl.glLineWidth(1)
@@ -748,6 +899,9 @@ class NWLazyMix(Operator, NWBase):
             if context.scene.NWBusyDrawing != 'STOP':
                 node1 = nodes[context.scene.NWBusyDrawing]
 
+        context.scene.NWLazySource = node1.name
+        context.scene.NWLazyTarget = node_at_pos(nodes, context, event).name
+
         if event.type == 'MOUSEMOVE':
             self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
 
@@ -804,6 +958,7 @@ class NWLazyConnect(Operator, NWBase):
     bl_idname = "node.nw_lazy_connect"
     bl_label = "Lazy Connect"
     bl_options = {'REGISTER', 'UNDO'}
+    with_menu = BoolProperty()
 
     def modal(self, context, event):
         context.area.tag_redraw()
@@ -821,6 +976,9 @@ class NWLazyConnect(Operator, NWBase):
             if context.scene.NWBusyDrawing != 'STOP':
                 node1 = nodes[context.scene.NWBusyDrawing]
 
+        context.scene.NWLazySource = node1.name
+        context.scene.NWLazyTarget = node_at_pos(nodes, context, event).name
+
         if event.type == 'MOUSEMOVE':
             self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
 
@@ -850,7 +1008,14 @@ class NWLazyConnect(Operator, NWBase):
                     node1.select = True
                     node2.select = True
 
-                    link_success = autolink(node1, node2, links)
+                    #link_success = autolink(node1, node2, links)
+                    if self.with_menu:
+                        if len(node1.outputs) > 1 and node2.inputs:
+                            bpy.ops.wm.call_menu("INVOKE_DEFAULT", name=NWConnectionListOutputs.bl_idname)
+                        elif len(node1.outputs) == 1:
+                            bpy.ops.node.nw_call_inputs_menu(from_socket=0)
+                    else:
+                        link_success = autolink(node1, node2, links)
 
                     for node in original_sel:
                         node.select = True
@@ -874,13 +1039,12 @@ class NWLazyConnect(Operator, NWBase):
             node = node_at_pos(nodes, context, event)
             if node:
                 context.scene.NWBusyDrawing = node.name
-                if node.outputs:
-                    context.scene.NWDrawColType = node.outputs[0].type
-            else:
-                context.scene.NWDrawColType = 'x'
 
             # the arguments we pass the the callback
-            args = (self, context, context.scene.NWDrawColType)
+            mode = "LINK"
+            if self.with_menu:
+                mode = "LINKMENU"
+            args = (self, context, mode)
             # Add the region OpenGL drawing callback
             # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
             self._handle = bpy.types.SpaceNodeEditor.draw_handler_add(draw_callback_mixnodes, args, 'WINDOW', 'POST_PIXEL')
@@ -2232,7 +2396,6 @@ class NWAlignNodes(Operator, NWBase):
                         parent = parent.parent
                     loc_x += offset_x + w
             else:  # if self.option == 'AXIS_Y'
-                #loc_x = (max_y_loc_x + max_y_w / 2.0 + min_y_loc_x + min_y_w / 2.0) / 2.0
                 loc_x = (max_x + max_x_w / 2.0 + min_x + min_x_w / 2.0) / 2.0
                 loc_y = min_y
                 offset_y = (max_y - min_y + total_h - min_y_h) / (count - 1)
@@ -2357,6 +2520,58 @@ class NWLinkToOutputNode(Operator, NWBase):
         return {'FINISHED'}
 
 
+class NWMakeLink(Operator, NWBase):
+    """Make a link from one socket to another"""
+    bl_idname = 'node.nw_make_link'
+    bl_label = 'Make Link'
+    bl_options = {'REGISTER', 'UNDO'}
+    from_socket = IntProperty()
+    to_socket = IntProperty()
+
+    @classmethod
+    def poll(cls, context):
+        snode = context.space_data
+        return (snode.type == 'NODE_EDITOR' and snode.node_tree is not None)
+
+    def execute(self, context):
+        nodes, links = get_nodes_links(context)
+
+        n1 = nodes[context.scene.NWLazySource]
+        n2 = nodes[context.scene.NWLazyTarget]
+
+        links.new(n1.outputs[self.from_socket], n2.inputs[self.to_socket])
+
+        hack_force_update(context, nodes)
+
+        return {'FINISHED'}
+
+
+class NWCallInputsMenu(Operator, NWBase):
+    """Link from this output"""
+    bl_idname = 'node.nw_call_inputs_menu'
+    bl_label = 'Make Link'
+    bl_options = {'REGISTER', 'UNDO'}
+    from_socket = IntProperty()
+
+    @classmethod
+    def poll(cls, context):
+        snode = context.space_data
+        return (snode.type == 'NODE_EDITOR' and snode.node_tree is not None)
+
+    def execute(self, context):
+        nodes, links = get_nodes_links(context)
+
+        context.scene.NWSourceSocket = self.from_socket
+
+        n1 = nodes[context.scene.NWLazySource]
+        n2 = nodes[context.scene.NWLazyTarget]
+        if len(n2.inputs) > 1:
+            bpy.ops.wm.call_menu("INVOKE_DEFAULT", name=NWConnectionListInputs.bl_idname)
+        elif len(n2.inputs) == 1:
+            links.new(n1.outputs[self.from_socket], n2.inputs[0])
+        return {'FINISHED'}
+
+
 #
 #  P A N E L
 #
@@ -2481,6 +2696,49 @@ class NWMergeMixMenu(Menu, NWBase):
             props.merge_type = 'MIX'
 
 
+class NWConnectionListOutputs(Menu, NWBase):
+    bl_idname = "NODE_MT_nw_connection_list_out"
+    bl_label = "From:"
+
+    def draw(self, context):
+        layout = self.layout
+        nodes, links = get_nodes_links(context)
+
+        n1 = nodes[context.scene.NWLazySource]
+
+        if n1.type == "R_LAYERS":
+            index=0
+            for o in n1.outputs:
+                if o.enabled:  # Check which passes the render layer has enabled
+                    layout.operator(NWCallInputsMenu.bl_idname, text=o.name, icon="RADIOBUT_OFF").from_socket=index
+                index+=1
+        else:
+            index=0
+            for o in n1.outputs:
+                layout.operator(NWCallInputsMenu.bl_idname, text=o.name, icon="RADIOBUT_OFF").from_socket=index
+                index+=1
+
+
+class NWConnectionListInputs(Menu, NWBase):
+    bl_idname = "NODE_MT_nw_connection_list_in"
+    bl_label = "To:"
+
+    def draw(self, context):
+        layout = self.layout
+        nodes, links = get_nodes_links(context)
+
+        n2 = nodes[context.scene.NWLazyTarget]
+
+        #print (self.from_socket)
+
+        index = 0
+        for i in n2.inputs:
+            op = layout.operator(NWMakeLink.bl_idname, text=i.name, icon="FORWARD")
+            op.from_socket = context.scene.NWSourceSocket
+            op.to_socket = index
+            index+=1
+
+
 class NWMergeMathMenu(Menu, NWBase):
     bl_idname = "NODE_MT_nw_merge_math_menu"
     bl_label = "Merge Selected Nodes using Math"
@@ -3114,6 +3372,8 @@ kmi_defs = (
     (NWLazyMix.bl_idname, 'RIGHTMOUSE', False, False, True, None, "Lazy Mix"),
     # Lazy Connect
     (NWLazyConnect.bl_idname, 'RIGHTMOUSE', True, False, False, None, "Lazy Connect"),
+    # Lazy Connect with Menu
+    (NWLazyConnect.bl_idname, 'RIGHTMOUSE', True, True, False, (('with_menu', True),), "Lazy Connect with Socket Menu"),
     # MENUS
     ('wm.call_menu', 'SPACE', True, False, False, (('name', NodeWranglerMenu.bl_idname),), "Node Wranger menu"),
     ('wm.call_menu', 'SLASH', False, False, False, (('name', NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
@@ -3131,10 +3391,18 @@ def register():
         name="Busy Drawing!",
         default="",
         description="An internal property used to store only the first mouse position")
-    bpy.types.Scene.NWDrawColType = StringProperty(
-        name="Color Type!",
+    bpy.types.Scene.NWLazySource = StringProperty(
+        name="Lazy Source!",
+        default="x",
+        description="An internal property used to store the first node in a Lazy Connect operation")
+    bpy.types.Scene.NWLazyTarget = StringProperty(
+        name="Lazy Target!",
         default="x",
-        description="An internal property used to store the line color")
+        description="An internal property used to store the last node in a Lazy Connect operation")
+    bpy.types.Scene.NWSourceSocket = IntProperty(
+        name="Source Socket!",
+        default=0,
+        description="An internal property used to store the source socket in a Lazy Connect operation")
 
     bpy.utils.register_module(__name__)
 
@@ -3157,7 +3425,9 @@ def register():
 def unregister():
     # props
     del bpy.types.Scene.NWBusyDrawing
-    del bpy.types.Scene.NWDrawColType
+    del bpy.types.Scene.NWLazySource
+    del bpy.types.Scene.NWLazyTarget
+    del bpy.types.Scene.NWSourceSocket
 
     bpy.utils.unregister_module(__name__)