diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs
index 871156662..af919c1f3 100644
--- a/Source/Editor/Options/InputOptions.cs
+++ b/Source/Editor/Options/InputOptions.cs
@@ -652,43 +652,47 @@ namespace FlaxEditor.Options
#endregion
- #region Node editors
+ #region Node Editors
[DefaultValue(typeof(InputBinding), "Shift+W")]
- [EditorDisplay("Node editors"), EditorOrder(4500)]
+ [EditorDisplay("Node Editors"), EditorOrder(4500)]
public InputBinding NodesAlignTop = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+A")]
- [EditorDisplay("Node editors"), EditorOrder(4510)]
+ [EditorDisplay("Node Editors"), EditorOrder(4510)]
public InputBinding NodesAlignLeft = new InputBinding(KeyboardKeys.A, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+S")]
- [EditorDisplay("Node editors"), EditorOrder(4520)]
+ [EditorDisplay("Node Editors"), EditorOrder(4520)]
public InputBinding NodesAlignBottom = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+D")]
- [EditorDisplay("Node editors"), EditorOrder(4530)]
+ [EditorDisplay("Node Editors"), EditorOrder(4530)]
public InputBinding NodesAlignRight = new InputBinding(KeyboardKeys.D, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Alt+Shift+W")]
- [EditorDisplay("Node editors"), EditorOrder(4540)]
+ [EditorDisplay("Node Editors"), EditorOrder(4540)]
public InputBinding NodesAlignMiddle = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Alt+Shift+S")]
- [EditorDisplay("Node editors"), EditorOrder(4550)]
+ [EditorDisplay("Node Editors"), EditorOrder(4550)]
public InputBinding NodesAlignCenter = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Q")]
- [EditorDisplay("Node editors"), EditorOrder(4560)]
+ [EditorDisplay("Node Editors"), EditorOrder(4560)]
public InputBinding NodesAutoFormat = new InputBinding(KeyboardKeys.Q);
- [DefaultValue(typeof(InputBinding), "None")]
- [EditorDisplay("Node editors"), EditorOrder(4570)]
- public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.None);
+ [DefaultValue(typeof(InputBinding), "Shift+Q")]
+ [EditorDisplay("Node Editors"), EditorOrder(4560)]
+ public InputBinding NodesStraightenConnections = new InputBinding(KeyboardKeys.Q, KeyboardKeys.Shift);
- [DefaultValue(typeof(InputBinding), "None")]
- [EditorDisplay("Node editors"), EditorOrder(4580)]
- public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.None);
+ [DefaultValue(typeof(InputBinding), "Alt+W")]
+ [EditorDisplay("Node Editors"), EditorOrder(4570)]
+ public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.W, KeyboardKeys.Alt);
+
+ [DefaultValue(typeof(InputBinding), "Alt+A")]
+ [EditorDisplay("Node Editors"), EditorOrder(4580)]
+ public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.A, KeyboardKeys.Alt);
#endregion
}
diff --git a/Source/Editor/Surface/NodeAlignmentType.cs b/Source/Editor/Surface/NodeAlignmentType.cs
index 141235783..07e1d8dc4 100644
--- a/Source/Editor/Surface/NodeAlignmentType.cs
+++ b/Source/Editor/Surface/NodeAlignmentType.cs
@@ -5,39 +5,39 @@ using FlaxEngine;
namespace FlaxEditor.Surface
{
///
- /// Node Alignment type
+ /// Node Alignment type.
///
[HideInEditor]
public enum NodeAlignmentType
{
///
- /// Align nodes vertically to top, matching top-most node
+ /// Align nodes vertically to top, matching top-most node.
///
Top,
///
- /// Align nodes vertically to middle, using average of all nodes
+ /// Align nodes vertically to middle, using average of all nodes.
///
Middle,
///
- /// Align nodes vertically to bottom, matching bottom-most node
+ /// Align nodes vertically to bottom, matching bottom-most node.
///
Bottom,
///
- /// Align nodes horizontally to left, matching left-most node
+ /// Align nodes horizontally to left, matching left-most node.
///
Left,
///
- /// Align nodes horizontally to center, using average of all nodes
+ /// Align nodes horizontally to center, using average of all nodes.
///
Center,
///
- /// Align nodes horizontally to right, matching right-most node
+ /// Align nodes horizontally to right, matching right-most node.
///
Right,
}
-}
\ No newline at end of file
+}
diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
index b1af9589b..2cd46593b 100644
--- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
+++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
@@ -28,7 +28,7 @@ namespace FlaxEditor.Surface
///
/// The input type to process.
/// Node groups cache that can be used for reusing groups for different nodes.
- /// The cache version number. Can be used to reject any cached data after rebuilt.
+ /// The cache version number. Can be used to reject any cached data after. rebuilt.
public delegate void IterateType(ScriptType scriptType, Dictionary, GroupArchetype> cache, int version);
internal static readonly List Caches = new List(8);
@@ -412,6 +412,7 @@ namespace FlaxEditor.Surface
_cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection;
_cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", Editor.Instance.Options.Options.Input.NodesAutoFormat, () => { FormatGraph(SelectedNodes); });
+ _cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Straighten connections", Editor.Instance.Options.Options.Input.NodesStraightenConnections, () => { StraightenGraphConnections(SelectedNodes); });
_cmFormatNodesMenu.ContextMenu.AddSeparator();
_cmAlignNodesTopButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align top", Editor.Instance.Options.Options.Input.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); });
diff --git a/Source/Editor/Surface/VisjectSurface.Formatting.cs b/Source/Editor/Surface/VisjectSurface.Formatting.cs
index 2ff48b290..39ac58242 100644
--- a/Source/Editor/Surface/VisjectSurface.Formatting.cs
+++ b/Source/Editor/Surface/VisjectSurface.Formatting.cs
@@ -1,9 +1,9 @@
+using FlaxEditor.Surface.Elements;
+using FlaxEditor.Surface.Undo;
+using FlaxEngine;
using System;
using System.Collections.Generic;
using System.Linq;
-using FlaxEngine;
-using FlaxEditor.Surface.Elements;
-using FlaxEditor.Surface.Undo;
namespace FlaxEditor.Surface
{
@@ -14,26 +14,26 @@ namespace FlaxEditor.Surface
private class NodeFormattingData
{
///
- /// Starting from 0 at the main nodes
+ /// Starting from 0 at the main nodes.
///
public int Layer;
///
- /// Position in the layer
+ /// Position in the layer.
///
public int Offset;
///
- /// How far the subtree needs to be moved additionally
+ /// How far the subtree needs to be moved additionally.
///
public int SubtreeOffset;
}
///
/// Formats a graph where the nodes can be disjointed.
- /// Uses the Sugiyama method
+ /// Uses the Sugiyama method.
///
- /// List of nodes
+ /// List of nodes.
public void FormatGraph(List nodes)
{
if (nodes.Count <= 1)
@@ -78,9 +78,9 @@ namespace FlaxEditor.Surface
}
///
- /// Formats a graph where all nodes are connected
+ /// Formats a graph where all nodes are connected.
///
- /// List of connected nodes
+ /// List of connected nodes.
protected void FormatConnectedGraph(List nodes)
{
if (nodes.Count <= 1)
@@ -160,11 +160,71 @@ namespace FlaxEditor.Surface
}
///
- /// Assigns a layer to every node
+ /// Straightens every connection between nodes in .
///
- /// The exta node data
- /// The end nodes
- /// The number of the maximum layer
+ /// List of nodes.
+ public void StraightenGraphConnections(List nodes)
+ {
+ if (nodes.Count <= 1)
+ return;
+
+ List undoActions = new List();
+
+ // Only process nodes that have any connection
+ List connectedNodes = nodes.Where(n => n.GetBoxes().Any(b => b.HasAnyConnection)).ToList();
+
+ if (connectedNodes.Count == 0)
+ return;
+
+ for (int i = 0; i < connectedNodes.Count - 1; i++)
+ {
+ SurfaceNode nodeA = connectedNodes[i];
+ List connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.IsOutput && b.HasAnyConnection).ToList();
+
+ for (int j = 0; j < connectedOutputBoxes.Count; j++)
+ {
+ Box boxA = connectedOutputBoxes[j];
+
+ for (int b = 0; b < boxA.Connections.Count; b++)
+ {
+ Box boxB = boxA.Connections[b];
+
+ // Ensure the other node is selected
+ if (!connectedNodes.Contains(boxB.ParentNode))
+ continue;
+
+ // Node with no outgoing connections reached. Advance to next node in list
+ if (boxA == null || boxB == null)
+ continue;
+
+ SurfaceNode nodeB = boxB.ParentNode;
+
+ // Calculate the Y offset needed for nodeB to align boxB's Y to boxA's Y
+ float boxASurfaceY = boxA.PointToParent(this, Float2.Zero).Y;
+ float boxBSurfaceY = boxB.PointToParent(this, Float2.Zero).Y;
+ float deltaY = (boxASurfaceY - boxBSurfaceY) / ViewScale;
+ Float2 delta = new Float2(0f, deltaY);
+
+ nodeB.Location += delta;
+
+ if (Undo != null)
+ undoActions.Add(new MoveNodesAction(Context, new[] { nodeB.ID }, delta));
+ }
+ }
+ }
+
+ if (undoActions.Count > 0)
+ Undo?.AddAction(new MultiUndoAction(undoActions, "Straightned "));
+
+ MarkAsEdited(false);
+ }
+
+ ///
+ /// Assigns a layer to every node.
+ ///
+ /// The exta node data.
+ /// The end nodes.
+ /// The number of the maximum layer.
private int SetLayers(Dictionary nodeData, List endNodes)
{
// Longest path layering
@@ -201,12 +261,12 @@ namespace FlaxEditor.Surface
///
- /// Sets the node offsets
+ /// Sets the node offsets.
///
- /// The exta node data
- /// The end nodes
- /// The number of the maximum layer
- /// The number of the maximum offset
+ /// The exta node data.
+ /// The end nodes.
+ /// The number of the maximum layer.
+ /// The number of the maximum offset.
private int SetOffsets(Dictionary nodeData, List endNodes, int maxLayer)
{
int maxOffset = 0;
@@ -287,10 +347,10 @@ namespace FlaxEditor.Surface
/// Align given nodes on a graph using the given alignment type.
/// Ignores any potential overlap.
///
- /// List of nodes
- /// Alignemnt type
+ /// List of nodes.
+ /// Alignemnt type.
public void AlignNodes(List nodes, NodeAlignmentType alignmentType)
- {
+ {
if(nodes.Count <= 1)
return;
@@ -328,8 +388,8 @@ namespace FlaxEditor.Surface
///
/// Distribute the given nodes as equally as possible inside the bounding box, if no fit can be done it will use a default pad of 10 pixels between nodes.
///
- /// List of nodes
- /// If false will be done horizontally, if true will be done vertically
+ /// List of nodes.
+ /// If false will be done horizontally, if true will be done vertically.
public void DistributeNodes(List nodes, bool vertically)
{
if(nodes.Count <= 1)
diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs
index 1201318d8..3bdad7eab 100644
--- a/Source/Editor/Surface/VisjectSurface.cs
+++ b/Source/Editor/Surface/VisjectSurface.cs
@@ -416,6 +416,7 @@ namespace FlaxEditor.Surface
new InputActionsContainer.Binding(options => options.Cut, Cut),
new InputActionsContainer.Binding(options => options.Duplicate, Duplicate),
new InputActionsContainer.Binding(options => options.NodesAutoFormat, () => { FormatGraph(SelectedNodes); }),
+ new InputActionsContainer.Binding(options => options.NodesStraightenConnections, () => { StraightenGraphConnections(SelectedNodes); }),
new InputActionsContainer.Binding(options => options.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }),
new InputActionsContainer.Binding(options => options.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }),
new InputActionsContainer.Binding(options => options.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }),