Merge branch 'xxSeys1-RipAppartAndConnectConnectionsVisject'
This commit is contained in:
@@ -34,11 +34,6 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// </summary>
|
||||
public const float DefaultConnectionOffset = 24f;
|
||||
|
||||
/// <summary>
|
||||
/// Distance for the mouse to be considered above the connection
|
||||
/// </summary>
|
||||
public float MouseOverConnectionDistance => 100f / Surface.ViewScale;
|
||||
|
||||
/// <inheritdoc />
|
||||
public OutputBox(SurfaceNode parentNode, NodeElementArchetype archetype)
|
||||
: base(parentNode, archetype, archetype.Position + new Float2(parentNode.Archetype.Size.X, 0))
|
||||
@@ -109,12 +104,13 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// </summary>
|
||||
/// <param name="targetBox">The other box.</param>
|
||||
/// <param name="mousePosition">The mouse position</param>
|
||||
public bool IntersectsConnection(Box targetBox, ref Float2 mousePosition)
|
||||
/// <param name="distance">Distance at which its an intersection</param>
|
||||
public bool IntersectsConnection(Box targetBox, ref Float2 mousePosition, float distance)
|
||||
{
|
||||
float connectionOffset = Mathf.Max(0f, DefaultConnectionOffset * (1 - Editor.Instance.Options.Options.Interface.ConnectionCurvature));
|
||||
Float2 start = new Float2(ConnectionOrigin.X + connectionOffset, ConnectionOrigin.Y);
|
||||
Float2 end = new Float2(targetBox.ConnectionOrigin.X - connectionOffset, targetBox.ConnectionOrigin.Y);
|
||||
return IntersectsConnection(ref start, ref end, ref mousePosition, MouseOverConnectionDistance);
|
||||
return IntersectsConnection(ref start, ref end, ref mousePosition, distance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +178,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
{
|
||||
// Draw all the connections
|
||||
var style = Surface.Style;
|
||||
var mouseOverDistance = MouseOverConnectionDistance;
|
||||
var mouseOverDistance = Surface.MouseOverConnectionDistance;
|
||||
var startPos = ConnectionOrigin;
|
||||
var startHighlight = ConnectionsHighlightIntensity;
|
||||
for (int i = 0; i < Connections.Count; i++)
|
||||
|
||||
@@ -213,6 +213,44 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw connection hints for lazy connect feature.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the contents of the surface (nodes, connections, comments, etc.).
|
||||
/// </summary>
|
||||
@@ -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
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static FlaxEditor.Surface.Archetypes.Particles;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEditor.Surface.Undo;
|
||||
@@ -23,12 +24,25 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public bool PanWithMiddleMouse = false;
|
||||
|
||||
/// <summary>
|
||||
/// Distance for the mouse to be considered above the connection.
|
||||
/// </summary>
|
||||
public float MouseOverConnectionDistance => 100f / ViewScale;
|
||||
|
||||
/// <summary>
|
||||
/// Distance of a node from which it is able to be slotted into an existing connection.
|
||||
/// </summary>
|
||||
public float SlotNodeIntoConnectionDistance => 250f / ViewScale;
|
||||
|
||||
private string _currentInputText = string.Empty;
|
||||
private Float2 _movingNodesDelta;
|
||||
private Float2 _gridRoundingDelta;
|
||||
private HashSet<SurfaceNode> _movingNodes;
|
||||
private HashSet<SurfaceNode> _temporarySelectedNodes;
|
||||
private readonly Stack<InputBracket> _inputBrackets = new Stack<InputBracket>();
|
||||
private bool _isLazyConnecting;
|
||||
private SurfaceNode _lazyConnectStartNode;
|
||||
private SurfaceNode _lazyConnectEndNode;
|
||||
private InputBinding _focusSelectedNodeBinding;
|
||||
|
||||
private class InputBracket
|
||||
@@ -251,8 +265,13 @@ namespace FlaxEditor.Surface
|
||||
// Cache mouse location
|
||||
_mousePos = location;
|
||||
|
||||
if (_isLazyConnecting && GetControlUnderMouse() is SurfaceNode nodeUnderMouse && !(nodeUnderMouse is SurfaceComment || nodeUnderMouse is ParticleEmitterNode))
|
||||
_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;
|
||||
@@ -322,6 +341,33 @@ namespace FlaxEditor.Surface
|
||||
|
||||
foreach (var node in _movingNodes)
|
||||
{
|
||||
// Allow ripping the node from its current connection
|
||||
if (RootWindow.GetKey(KeyboardKeys.Alt))
|
||||
{
|
||||
InputBox nodeConnectedInput = null;
|
||||
OutputBox nodeConnectedOuput = null;
|
||||
|
||||
var boxes = node.GetBoxes();
|
||||
foreach (var box in boxes)
|
||||
{
|
||||
if (!box.IsOutput && box.Connections.Count > 0)
|
||||
{
|
||||
nodeConnectedInput = (InputBox)box;
|
||||
continue;
|
||||
}
|
||||
if (box.IsOutput && box.Connections.Count > 0)
|
||||
{
|
||||
nodeConnectedOuput = (OutputBox)box;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeConnectedInput != null && nodeConnectedOuput != null)
|
||||
TryConnect(nodeConnectedOuput.Connections[0], nodeConnectedInput.Connections[0]);
|
||||
|
||||
node.RemoveConnections();
|
||||
}
|
||||
|
||||
if (gridSnap)
|
||||
{
|
||||
Float2 unroundedLocation = node.Location;
|
||||
@@ -421,7 +467,7 @@ namespace FlaxEditor.Surface
|
||||
if (!handled && CanEdit && CanUseNodeType(7, 29))
|
||||
{
|
||||
var mousePos = _rootControl.PointFromParent(ref _mousePos);
|
||||
if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox) && GetControlUnderMouse() == null)
|
||||
if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox, MouseOverConnectionDistance) && GetControlUnderMouse() == null)
|
||||
{
|
||||
if (Undo != null)
|
||||
{
|
||||
@@ -516,11 +562,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 && !(controlUnderMouse is SurfaceComment || controlUnderMouse is ParticleEmitterNode))
|
||||
_lazyConnectStartNode = node;
|
||||
|
||||
// Check if mouse is over header and user is pressing mouse left button
|
||||
if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation))
|
||||
{
|
||||
@@ -555,6 +607,9 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_isLazyConnecting && Nodes.Count > 0)
|
||||
_lazyConnectStartNode = GetClosestNodeAtLocation(location);
|
||||
|
||||
// Cache flags and state
|
||||
if (_leftMouseDown)
|
||||
{
|
||||
@@ -603,8 +658,71 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
if (_movingNodes != null && _movingNodes.Count > 0)
|
||||
{
|
||||
// Allow dropping a single node onto an existing connection and connect it
|
||||
if (_movingNodes.Count == 1)
|
||||
{
|
||||
var mousePos = _rootControl.PointFromParent(ref _mousePos);
|
||||
InputBox intersectedConnectionInputBox;
|
||||
OutputBox intersectedConnectionOutputBox;
|
||||
if (IntersectsConnection(mousePos, out intersectedConnectionInputBox, out intersectedConnectionOutputBox, SlotNodeIntoConnectionDistance))
|
||||
{
|
||||
SurfaceNode node = _movingNodes.First();
|
||||
InputBox nodeInputBox = (InputBox)node.GetBoxes().First(b => !b.IsOutput);
|
||||
OutputBox nodeOutputBox = (OutputBox)node.GetBoxes().First(b => b.IsOutput);
|
||||
TryConnect(intersectedConnectionOutputBox, nodeInputBox);
|
||||
TryConnect(nodeOutputBox, intersectedConnectionInputBox);
|
||||
|
||||
float intersectedConnectionNodesXDistance = intersectedConnectionInputBox.ParentNode.Left - intersectedConnectionOutputBox.ParentNode.Right;
|
||||
float paddedNodeWidth = node.Width + 2f;
|
||||
if (intersectedConnectionNodesXDistance < paddedNodeWidth)
|
||||
{
|
||||
List<SurfaceNode> visitedNodes = new List<SurfaceNode>{ node };
|
||||
List<SurfaceNode> movedNodes = new List<SurfaceNode>();
|
||||
Float2 locationDelta = new Float2(paddedNodeWidth, 0f);
|
||||
|
||||
MoveConnectedNodes(intersectedConnectionInputBox.ParentNode);
|
||||
|
||||
void MoveConnectedNodes(SurfaceNode node)
|
||||
{
|
||||
// Only move node if it is to the right of the node we have connected the moved node to
|
||||
if (node.Right > intersectedConnectionInputBox.ParentNode.Left + 15f && !node.Archetype.Flags.HasFlag(NodeFlags.NoMove))
|
||||
{
|
||||
node.Location += locationDelta;
|
||||
movedNodes.Add(node);
|
||||
}
|
||||
|
||||
visitedNodes.Add(node);
|
||||
|
||||
foreach (var box in node.GetBoxes())
|
||||
{
|
||||
if (!box.HasAnyConnection || box == intersectedConnectionInputBox)
|
||||
continue;
|
||||
|
||||
foreach (var connectedBox in box.Connections)
|
||||
{
|
||||
SurfaceNode nextNode = connectedBox.ParentNode;
|
||||
if (visitedNodes.Contains(nextNode))
|
||||
continue;
|
||||
|
||||
MoveConnectedNodes(nextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Float2 nodeMoveOffset = new Float2(node.Width * 0.5f, 0f);
|
||||
node.Location += nodeMoveOffset;
|
||||
|
||||
var moveNodesAction = new MoveNodesAction(Context, movedNodes.Select(n => n.ID).ToArray(), locationDelta);
|
||||
var moveNodeAction = new MoveNodesAction(Context, [node.ID], nodeMoveOffset);
|
||||
var multiAction = new MultiUndoAction(moveNodeAction, moveNodesAction);
|
||||
|
||||
AddBatchedUndoAction(multiAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Undo != null && !_movingNodesDelta.IsZero && CanEdit)
|
||||
Undo.AddAction(new MoveNodesAction(Context, _movingNodes.Select(x => x.ID).ToArray(), _movingNodesDelta));
|
||||
AddBatchedUndoAction(new MoveNodesAction(Context, _movingNodes.Select(x => x.ID).ToArray(), _movingNodesDelta));
|
||||
_movingNodes.Clear();
|
||||
}
|
||||
_movingNodesDelta = Float2.Zero;
|
||||
@@ -631,12 +749,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)
|
||||
{
|
||||
@@ -652,7 +794,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
// Surface was not moved with MMB so try to remove connection underneath
|
||||
var mousePos = _rootControl.PointFromParent(ref location);
|
||||
if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox))
|
||||
if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox, MouseOverConnectionDistance))
|
||||
{
|
||||
var action = new EditNodeConnections(inputBox.ParentNode.Context, inputBox.ParentNode);
|
||||
inputBox.BreakConnection(outputBox);
|
||||
@@ -846,6 +988,29 @@ namespace FlaxEditor.Surface
|
||||
return false;
|
||||
}
|
||||
|
||||
private SurfaceNode GetClosestNodeAtLocation(Float2 location)
|
||||
{
|
||||
SurfaceNode currentClosestNode = null;
|
||||
float currentClosestDistanceSquared = float.MaxValue;
|
||||
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
if (node is SurfaceComment || node is ParticleEmitterNode)
|
||||
continue;
|
||||
|
||||
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 = "";
|
||||
@@ -1035,7 +1200,7 @@ namespace FlaxEditor.Surface
|
||||
return new Float2(xLocation, yLocation);
|
||||
}
|
||||
|
||||
private bool IntersectsConnection(Float2 mousePosition, out InputBox inputBox, out OutputBox outputBox)
|
||||
private bool IntersectsConnection(Float2 mousePosition, out InputBox inputBox, out OutputBox outputBox, float distance)
|
||||
{
|
||||
for (int i = 0; i < Nodes.Count; i++)
|
||||
{
|
||||
@@ -1045,7 +1210,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
for (int k = 0; k < ob.Connections.Count; k++)
|
||||
{
|
||||
if (ob.IntersectsConnection(ob.Connections[k], ref mousePosition))
|
||||
if (ob.IntersectsConnection(ob.Connections[k], ref mousePosition, distance))
|
||||
{
|
||||
outputBox = ob;
|
||||
inputBox = ob.Connections[k] as InputBox;
|
||||
|
||||
Reference in New Issue
Block a user