diff --git a/Source/Editor/Surface/VisjectSurface.Draw.cs b/Source/Editor/Surface/VisjectSurface.Draw.cs
index af5893907..d79b21e9c 100644
--- a/Source/Editor/Surface/VisjectSurface.Draw.cs
+++ b/Source/Editor/Surface/VisjectSurface.Draw.cs
@@ -213,6 +213,44 @@ namespace FlaxEditor.Surface
}
}
+ ///
+ /// Draw connection hints for lazy connect feature.
+ ///
+ protected virtual void DrawLazyConnect()
+ {
+ var style = FlaxEngine.GUI.Style.Current;
+
+ if (_lazyConnectStartNode != null)
+ {
+ Float2 upperLeft = _rootControl.PointToParent(_lazyConnectStartNode.UpperLeft);
+ Rectangle startNodeOutline = new Rectangle(upperLeft + 1f, _lazyConnectStartNode.Size - 1f);
+ startNodeOutline.Size *= ViewScale;
+ Render2D.DrawRectangle(startNodeOutline.MakeExpanded(4f), style.BackgroundSelected, 4f);
+ }
+
+ if (_lazyConnectEndNode != null)
+ {
+ Float2 upperLeft = _rootControl.PointToParent(_lazyConnectEndNode.UpperLeft);
+ Rectangle startNodeOutline = new Rectangle(upperLeft + 1f, _lazyConnectEndNode.Size - 1f);
+ startNodeOutline.Size *= ViewScale;
+ Render2D.DrawRectangle(startNodeOutline.MakeExpanded(4f), style.BackgroundSelected, 4f);
+ }
+
+ Rectangle startRect = new Rectangle(_rightMouseDownPos - 6f, new Float2(12f));
+ Rectangle endRect = new Rectangle(_mousePos - 6f, new Float2(12f));
+
+ // Start and end shadows/ outlines
+ Render2D.FillRectangle(startRect.MakeExpanded(2.5f), Color.Black);
+ Render2D.FillRectangle(endRect.MakeExpanded(2.5f), Color.Black);
+
+ Render2D.DrawLine(_rightMouseDownPos, _mousePos, Color.Black, 7.5f);
+ Render2D.DrawLine(_rightMouseDownPos, _mousePos, style.ForegroundGrey, 5f);
+
+ // Draw start and end boxes over the lines to hide ugly artifacts at the ends
+ Render2D.FillRectangle(startRect, style.ForegroundGrey);
+ Render2D.FillRectangle(endRect, style.ForegroundGrey);
+ }
+
///
/// Draws the contents of the surface (nodes, connections, comments, etc.).
///
@@ -260,6 +298,9 @@ namespace FlaxEditor.Surface
DrawContents();
+ if (_isLazyConnecting)
+ DrawLazyConnect();
+
//Render2D.DrawText(style.FontTitle, string.Format("Scale: {0}", _rootControl.Scale), rect, Enabled ? Color.Red : Color.Black);
// Draw border
diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs
index 388df0b9c..f7d90512e 100644
--- a/Source/Editor/Surface/VisjectSurface.Input.cs
+++ b/Source/Editor/Surface/VisjectSurface.Input.cs
@@ -29,6 +29,9 @@ namespace FlaxEditor.Surface
private HashSet _movingNodes;
private HashSet _temporarySelectedNodes;
private readonly Stack _inputBrackets = new Stack();
+ private bool _isLazyConnecting;
+ private SurfaceNode _lazyConnectStartNode;
+ private SurfaceNode _lazyConnectEndNode;
private class InputBracket
{
@@ -250,8 +253,13 @@ namespace FlaxEditor.Surface
// Cache mouse location
_mousePos = location;
+ if (_isLazyConnecting && GetControlUnderMouse() is SurfaceNode nodeUnderMouse)
+ _lazyConnectEndNode = nodeUnderMouse;
+ else if (_isLazyConnecting && Nodes.Count > 0)
+ _lazyConnectEndNode = GetClosestNodeAtLocation(location);
+
// Moving around surface with mouse
- if (_rightMouseDown)
+ if (_rightMouseDown && !_isLazyConnecting)
{
// Calculate delta
var delta = location - _rightMouseDownPos;
@@ -542,11 +550,17 @@ namespace FlaxEditor.Surface
_middleMouseDownPos = location;
}
+ if (root.GetKey(KeyboardKeys.Alt) && button == MouseButton.Right)
+ _isLazyConnecting = true;
+
// Check if any node is under the mouse
SurfaceControl controlUnderMouse = GetControlUnderMouse();
var cLocation = _rootControl.PointFromParent(ref location);
if (controlUnderMouse != null)
{
+ if (controlUnderMouse is SurfaceNode node && _isLazyConnecting)
+ _lazyConnectStartNode = node;
+
// Check if mouse is over header and user is pressing mouse left button
if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation))
{
@@ -581,6 +595,9 @@ namespace FlaxEditor.Surface
}
else
{
+ if (_isLazyConnecting && Nodes.Count > 0)
+ _lazyConnectStartNode = GetClosestNodeAtLocation(location);
+
// Cache flags and state
if (_leftMouseDown)
{
@@ -720,12 +737,36 @@ namespace FlaxEditor.Surface
{
// Check if any control is under the mouse
_cmStartPos = location;
- if (controlUnderMouse == null)
+ if (controlUnderMouse == null && !_isLazyConnecting)
{
showPrimaryMenu = true;
}
}
_mouseMoveAmount = 0;
+
+ if (_isLazyConnecting)
+ {
+ if (_lazyConnectStartNode != null && _lazyConnectEndNode != null && _lazyConnectStartNode != _lazyConnectEndNode)
+ {
+ // First check if there is a type matching input and output where input
+ OutputBox startNodeOutput = (OutputBox)_lazyConnectStartNode.GetBoxes().FirstOrDefault(b => b.IsOutput, null);
+ InputBox endNodeInput = null;
+
+ if (startNodeOutput != null)
+ endNodeInput = (InputBox)_lazyConnectEndNode.GetBoxes().FirstOrDefault(b => !b.IsOutput && b.CurrentType == startNodeOutput.CurrentType && !b.HasAnyConnection && b.IsActive && b.CanConnectWith(startNodeOutput), null);
+
+ // Perform less strict checks (less ideal conditions for connection but still good) if the first checks failed
+ if (endNodeInput == null)
+ endNodeInput = (InputBox)_lazyConnectEndNode.GetBoxes().FirstOrDefault(b => !b.IsOutput && !b.HasAnyConnection && b.CanConnectWith(startNodeOutput), null);
+
+ if (startNodeOutput != null && endNodeInput != null)
+ TryConnect(startNodeOutput, endNodeInput);
+ }
+
+ _isLazyConnecting = false;
+ _lazyConnectStartNode = null;
+ _lazyConnectEndNode = null;
+ }
}
if (_middleMouseDown && button == MouseButton.Middle)
{
@@ -927,6 +968,26 @@ namespace FlaxEditor.Surface
return false;
}
+ private SurfaceNode GetClosestNodeAtLocation(Float2 location)
+ {
+ SurfaceNode currentClosestNode = null;
+ float currentClosestDistanceSquared = float.MaxValue;
+
+ foreach (var node in Nodes)
+ {
+ Float2 nodeSurfaceLocation = _rootControl.PointToParent(node.Center);
+
+ float distanceSquared = Float2.DistanceSquared(location, nodeSurfaceLocation);
+ if (distanceSquared < currentClosestDistanceSquared)
+ {
+ currentClosestNode = node;
+ currentClosestDistanceSquared = distanceSquared;
+ }
+ }
+
+ return currentClosestNode;
+ }
+
private void ResetInput()
{
InputText = "";