Basic reroute nodes
This commit is contained in:
@@ -983,6 +983,115 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
private class RerouteNode : SurfaceNode
|
||||
{
|
||||
public static readonly Vector2 DefaultSize = new Vector2(16);
|
||||
|
||||
private bool _deleteNode;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool ShowTooltip => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public RerouteNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
{
|
||||
Size = DefaultSize;
|
||||
Title = string.Empty;
|
||||
BackgroundColor = Color.Transparent;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSurfaceLoaded()
|
||||
{
|
||||
base.OnSurfaceLoaded();
|
||||
|
||||
var inputBox = GetBox(0);
|
||||
var outputBox = GetBox(1);
|
||||
inputBox.Location = Vector2.Zero;
|
||||
outputBox.Location = Vector2.Zero;
|
||||
|
||||
inputBox.Visible = false;
|
||||
outputBox.Visible = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ConnectionTick(Box box)
|
||||
{
|
||||
base.ConnectionTick(box);
|
||||
|
||||
var inputBox = GetBox(0);
|
||||
var outputBox = GetBox(1);
|
||||
|
||||
_deleteNode = !inputBox.HasAnyConnection;
|
||||
outputBox.Visible = !outputBox.HasAnyConnection;
|
||||
}
|
||||
|
||||
/*public override void OnDeleted()
|
||||
{
|
||||
var inputBox = GetBox(0);
|
||||
var outputBox = GetBox(1);
|
||||
|
||||
var connectionA = inputBox.HasAnyConnection ? inputBox.Connections[0] : null; // This doesn't work
|
||||
var connectionB = outputBox.HasAnyConnection ? outputBox.Connections[0] : null;
|
||||
|
||||
base.OnDeleted();
|
||||
|
||||
if (connectionA != null && connectionB != null)
|
||||
{
|
||||
connectionA.CreateConnection(connectionB); // TODO: handle undo
|
||||
}
|
||||
}*/
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (_deleteNode)
|
||||
{
|
||||
_deleteNode = false;
|
||||
Surface.Delete(this); // TODO: handle undo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanSelect(ref Vector2 location)
|
||||
{
|
||||
return new Rectangle(Location, DefaultSize).Contains(ref location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateRectangles()
|
||||
{
|
||||
_headerRect = Rectangle.Empty;
|
||||
_closeButtonRect = Rectangle.Empty;
|
||||
_footerRect = Rectangle.Empty;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
var style = Surface.Style;
|
||||
var inputBox = GetBox(0);
|
||||
var connectionColor = style.Colors.Default;
|
||||
|
||||
if (inputBox.HasAnyConnection)
|
||||
{
|
||||
var hints = inputBox.Connections[0].ParentNode.Archetype.ConnectionsHints;
|
||||
Surface.Style.GetConnectionColor(inputBox.Connections[0].CurrentType, hints, out connectionColor);
|
||||
}
|
||||
|
||||
//float barHeight = 4;
|
||||
//Render2D.FillRectangle(new Rectangle(DefaultSize.X / 2, (DefaultSize.Y - barHeight) / 2, barHeight * 4, barHeight), connectionColor);
|
||||
|
||||
SpriteHandle icon = style.Icons.BoxClose;
|
||||
Render2D.DrawSprite(icon, new Rectangle(Vector2.Zero, DefaultSize), connectionColor);
|
||||
|
||||
base.Draw();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The nodes for that group.
|
||||
/// </summary>
|
||||
@@ -1438,6 +1547,23 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(object), 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 29,
|
||||
Title = "Reroute",
|
||||
Create = (id, context, arch, groupArch) => new RerouteNode(id, context, arch, groupArch),
|
||||
Description = "Reroute a connection.",
|
||||
Flags = NodeFlags.NoCloseButton | NodeFlags.NoSpawnViaGUI | NodeFlags.AllGraphs,
|
||||
Size = RerouteNode.DefaultSize,
|
||||
ConnectionsHints = ConnectionsHint.All,
|
||||
IndependentBoxes = new int[] { 0 },
|
||||
DependentBoxes = new int[] { 1 },
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, null, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, null, 1),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace FlaxEditor.Surface.Elements
|
||||
[HideInEditor]
|
||||
public class OutputBox : Box
|
||||
{
|
||||
/// <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 Vector2(parentNode.Archetype.Size.X, 0))
|
||||
@@ -44,6 +49,18 @@ namespace FlaxEditor.Surface.Elements
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a point intersects a connection
|
||||
/// </summary>
|
||||
/// <param name="targetBox">The other box.</param>
|
||||
/// <param name="mousePosition">The mouse position</param>
|
||||
public bool IntersectsConnection(Box targetBox, ref Vector2 mousePosition)
|
||||
{
|
||||
var startPos = Parent.PointToParent(Center);
|
||||
Vector2 endPos = targetBox.Parent.PointToParent(targetBox.Center);
|
||||
return IntersectsConnection(ref startPos, ref endPos, ref mousePosition, MouseOverConnectionDistance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a point intersects a bezier curve
|
||||
/// </summary>
|
||||
@@ -53,8 +70,6 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// <param name="distance">Distance at which its an intersection</param>
|
||||
public static bool IntersectsConnection(ref Vector2 start, ref Vector2 end, ref Vector2 point, float distance)
|
||||
{
|
||||
// Maybe I should make this a non-static method and automatically read the Surface.ViewScale?
|
||||
|
||||
// Pretty much a point in rectangle check
|
||||
if ((point.X - start.X) * (end.X - point.X) < 0) return false;
|
||||
|
||||
@@ -82,6 +97,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
float t = i * segmentCountInv;
|
||||
Bezier(ref start, ref control1, ref control2, ref end, t, out p);
|
||||
|
||||
// Maybe it would be reasonable to return the point?
|
||||
CollisionsHelper.ClosestPointPointLine(ref point, ref oldp, ref p, out Vector2 result);
|
||||
if (Vector2.DistanceSquared(point, result) <= squaredDistance)
|
||||
{
|
||||
@@ -106,22 +122,21 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// </summary>
|
||||
public void DrawConnections(ref Vector2 mousePosition)
|
||||
{
|
||||
float mouseOverDistance = MouseOverConnectionDistance;
|
||||
// Draw all the connections
|
||||
var center = Size * 0.5f;
|
||||
var tmp = PointToParent(ref center);
|
||||
var startPos = Parent.PointToParent(ref tmp);
|
||||
var startPos = Parent.PointToParent(Center);
|
||||
var startHighlight = ConnectionsHighlightIntensity;
|
||||
for (int i = 0; i < Connections.Count; i++)
|
||||
{
|
||||
Box targetBox = Connections[i];
|
||||
tmp = targetBox.PointToParent(ref center);
|
||||
Vector2 endPos = targetBox.Parent.PointToParent(ref tmp);
|
||||
Vector2 endPos = targetBox.Parent.PointToParent(targetBox.Center);
|
||||
var highlight = 1 + Mathf.Max(startHighlight, targetBox.ConnectionsHighlightIntensity);
|
||||
var color = _currentTypeColor * highlight;
|
||||
|
||||
if (IntersectsConnection(ref startPos, ref endPos, ref mousePosition, 100f / Surface.ViewScale))
|
||||
// TODO: Figure out how to only draw the topmost connection
|
||||
if (IntersectsConnection(ref startPos, ref endPos, ref mousePosition, mouseOverDistance))
|
||||
{
|
||||
highlight += 2;
|
||||
highlight += 1;
|
||||
}
|
||||
|
||||
DrawConnection(ref startPos, ref endPos, ref color, highlight);
|
||||
@@ -134,11 +149,8 @@ namespace FlaxEditor.Surface.Elements
|
||||
public void DrawSelectedConnection(Box targetBox)
|
||||
{
|
||||
// Draw all the connections
|
||||
var center = Size * 0.5f;
|
||||
var tmp = PointToParent(ref center);
|
||||
var startPos = Parent.PointToParent(ref tmp);
|
||||
tmp = targetBox.PointToParent(ref center);
|
||||
Vector2 endPos = targetBox.Parent.PointToParent(ref tmp);
|
||||
var startPos = Parent.PointToParent(Center);
|
||||
Vector2 endPos = targetBox.Parent.PointToParent(targetBox.Center);
|
||||
DrawConnection(ref startPos, ref endPos, ref _currentTypeColor, 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ namespace FlaxEditor.Surface
|
||||
AutoFocus = false;
|
||||
TooltipText = nodeArch.Description;
|
||||
CullChildren = false;
|
||||
BackgroundColor = Style.Current.BackgroundNormal;
|
||||
|
||||
if (Archetype.DefaultValues != null)
|
||||
{
|
||||
@@ -947,7 +948,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Background
|
||||
var backgroundRect = new Rectangle(Vector2.Zero, Size);
|
||||
Render2D.FillRectangle(backgroundRect, style.BackgroundNormal);
|
||||
Render2D.FillRectangle(backgroundRect, BackgroundColor);
|
||||
|
||||
// Breakpoint hit
|
||||
if (Breakpoint.Hit)
|
||||
|
||||
@@ -274,12 +274,24 @@ namespace FlaxEditor.Surface
|
||||
bool handled = base.OnMouseDoubleClick(location, button);
|
||||
if (!handled)
|
||||
CustomMouseDoubleClick?.Invoke(ref location, button, ref handled);
|
||||
if (handled)
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
return true;
|
||||
var mousePos = _rootControl.PointFromParent(ref _mousePos);
|
||||
if (IntersectsConnection(mousePos, out OutputBox outputBox, out Box connectedBox))
|
||||
{
|
||||
var rerouteNode = Context.SpawnNode(7, 29, mousePos);
|
||||
|
||||
// TODO: Undo action
|
||||
outputBox.BreakConnection(connectedBox);
|
||||
outputBox.CreateConnection(rerouteNode.GetBoxes().First(b => !b.IsOutput));
|
||||
rerouteNode.GetBoxes().First(b => b.IsOutput).CreateConnection(connectedBox);
|
||||
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return handled;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -815,5 +827,31 @@ namespace FlaxEditor.Surface
|
||||
yLocation
|
||||
);
|
||||
}
|
||||
|
||||
private bool IntersectsConnection(Vector2 mousePosition, out OutputBox outputBox, out Box connectedBox)
|
||||
{
|
||||
for (int i = 0; i < Nodes.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < Nodes[i].Elements.Count; j++)
|
||||
{
|
||||
if (Nodes[i].Elements[j] is OutputBox ob)
|
||||
{
|
||||
for (int k = 0; k < ob.Connections.Count; k++)
|
||||
{
|
||||
if (ob.IntersectsConnection(ob.Connections[k], ref mousePosition))
|
||||
{
|
||||
outputBox = ob;
|
||||
connectedBox = ob.Connections[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputBox = null;
|
||||
connectedBox = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user