Merge remote-tracking branch 'origin/1.12' into 1.12
This commit is contained in:
@@ -175,15 +175,13 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
}
|
||||
|
||||
bool isExpanded = isAnyChildVisible;
|
||||
|
||||
if (isExpanded)
|
||||
if (!noFilter)
|
||||
{
|
||||
Expand(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Collapse(true);
|
||||
bool isExpanded = isAnyChildVisible;
|
||||
if (isExpanded)
|
||||
Expand(true);
|
||||
else
|
||||
Collapse(true);
|
||||
}
|
||||
|
||||
Visible = isThisVisible | isAnyChildVisible;
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace FlaxEditor.CustomEditors
|
||||
private readonly List<CustomEditor> _children = new List<CustomEditor>();
|
||||
private ValueContainer _values;
|
||||
private bool _isSetBlocked;
|
||||
private bool _isRebuilding;
|
||||
private bool _skipChildrenRefresh;
|
||||
private bool _hasValueDirty;
|
||||
private bool _rebuildOnRefresh;
|
||||
@@ -178,7 +179,7 @@ namespace FlaxEditor.CustomEditors
|
||||
public void RebuildLayout()
|
||||
{
|
||||
// Skip rebuilding during init
|
||||
if (CurrentCustomEditor == this)
|
||||
if (CurrentCustomEditor == this || _isRebuilding)
|
||||
return;
|
||||
|
||||
// Special case for root objects to run normal layout build
|
||||
@@ -197,6 +198,7 @@ namespace FlaxEditor.CustomEditors
|
||||
_parent?.RebuildLayout();
|
||||
return;
|
||||
}
|
||||
_isRebuilding = true;
|
||||
var control = layout.ContainerControl;
|
||||
var parent = _parent;
|
||||
var parentScrollV = (_presenter?.Panel.Parent as Panel)?.VScrollBar?.Value ?? -1;
|
||||
@@ -216,6 +218,7 @@ namespace FlaxEditor.CustomEditors
|
||||
// Restore scroll value
|
||||
if (parentScrollV > -1 && _presenter != null && _presenter.Panel.Parent is Panel panel && panel.VScrollBar != null)
|
||||
panel.VScrollBar.Value = parentScrollV;
|
||||
_isRebuilding = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -61,6 +61,7 @@ public class Editor : EditorModule
|
||||
options.PrivateDependencies.Add("Renderer");
|
||||
options.PrivateDependencies.Add("TextureTool");
|
||||
options.PrivateDependencies.Add("Particles");
|
||||
options.PrivateDependencies.Add("Terrain");
|
||||
|
||||
var platformToolsRoot = Path.Combine(FolderPath, "Cooker", "Platform");
|
||||
var platformToolsRootExternal = Path.Combine(Globals.EngineRoot, "Source", "Platforms");
|
||||
|
||||
@@ -135,11 +135,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.MaximumSize = Float2.Zero; // Unlimited size
|
||||
settings.Fullscreen = false;
|
||||
settings.HasBorder = true;
|
||||
#if PLATFORM_SDL
|
||||
settings.SupportsTransparency = true;
|
||||
#else
|
||||
settings.SupportsTransparency = false;
|
||||
#endif
|
||||
settings.ActivateWhenFirstShown = true;
|
||||
settings.AllowInput = true;
|
||||
settings.AllowMinimize = true;
|
||||
@@ -211,6 +207,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
if (ChildPanelsCount > 0)
|
||||
return;
|
||||
|
||||
// Close window
|
||||
_window?.Close();
|
||||
}
|
||||
|
||||
@@ -269,8 +269,9 @@ namespace FlaxEditor.GUI.Docking
|
||||
if (_toDock == null)
|
||||
return;
|
||||
|
||||
if (_toDock.RootWindow.Window != _dragSourceWindow)
|
||||
_toDock.RootWindow.Window.MouseUp -= OnMouseUp;
|
||||
var window = _toDock.RootWindow?.Window;
|
||||
if (window != null && window != _dragSourceWindow)
|
||||
window.MouseUp -= OnMouseUp;
|
||||
|
||||
_dockHintDown?.Parent.RemoveChild(_dockHintDown);
|
||||
_dockHintUp?.Parent.RemoveChild(_dockHintUp);
|
||||
@@ -327,10 +328,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
_toDock?.RootWindow.Window.BringToFront();
|
||||
//_toDock?.RootWindow.Window.Focus();
|
||||
|
||||
#if PLATFORM_SDL
|
||||
// Make the dragged window transparent when dock hints are visible
|
||||
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
|
||||
#else
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Bring the drop source always to the top
|
||||
if (_dragSourceWindow != null)
|
||||
_dragSourceWindow.BringToFront();
|
||||
|
||||
267
Source/Editor/Gizmo/DirectionGizmo.cs
Normal file
267
Source/Editor/Gizmo/DirectionGizmo.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Viewport;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Gizmo;
|
||||
|
||||
[HideInEditor]
|
||||
internal class DirectionGizmo : ContainerControl
|
||||
{
|
||||
private IGizmoOwner _owner;
|
||||
private ViewportProjection _viewportProjection;
|
||||
private EditorViewport _viewport;
|
||||
private Vector3 _gizmoCenter;
|
||||
private float _axisLength = 75.0f;
|
||||
private float _textAxisLength = 95.0f;
|
||||
private float _spriteRadius = 12.0f;
|
||||
|
||||
private AxisData _xAxisData;
|
||||
private AxisData _yAxisData;
|
||||
private AxisData _zAxisData;
|
||||
private AxisData _negXAxisData;
|
||||
private AxisData _negYAxisData;
|
||||
private AxisData _negZAxisData;
|
||||
|
||||
private List<AxisData> _axisData = new List<AxisData>();
|
||||
private int _hoveredAxisIndex = -1;
|
||||
|
||||
private SpriteHandle _posHandle;
|
||||
private SpriteHandle _negHandle;
|
||||
|
||||
private FontReference _fontReference;
|
||||
|
||||
// Store sprite positions for hover detection
|
||||
private List<(Float2 position, AxisDirection direction)> _spritePositions = new List<(Float2, AxisDirection)>();
|
||||
|
||||
private struct ViewportProjection
|
||||
{
|
||||
private Matrix _viewProjection;
|
||||
private BoundingFrustum _frustum;
|
||||
private FlaxEngine.Viewport _viewport;
|
||||
private Vector3 _origin;
|
||||
|
||||
public void Init(EditorViewport editorViewport)
|
||||
{
|
||||
// Inline EditorViewport.ProjectPoint to save on calculation for large set of points
|
||||
_viewport = new FlaxEngine.Viewport(0, 0, editorViewport.Width, editorViewport.Height);
|
||||
_frustum = editorViewport.ViewFrustum;
|
||||
_viewProjection = _frustum.Matrix;
|
||||
_origin = editorViewport.Task.View.Origin;
|
||||
}
|
||||
|
||||
public void ProjectPoint(Vector3 worldSpaceLocation, out Float2 viewportSpaceLocation)
|
||||
{
|
||||
worldSpaceLocation -= _origin;
|
||||
_viewport.Project(ref worldSpaceLocation, ref _viewProjection, out var projected);
|
||||
viewportSpaceLocation = new Float2((float)projected.X, (float)projected.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private struct AxisData
|
||||
{
|
||||
public Float2 Delta;
|
||||
public float Distance;
|
||||
public string Label;
|
||||
public Color AxisColor;
|
||||
public bool Negative;
|
||||
public AxisDirection Direction;
|
||||
}
|
||||
|
||||
private enum AxisDirection
|
||||
{
|
||||
PosX,
|
||||
PosY,
|
||||
PosZ,
|
||||
NegX,
|
||||
NegY,
|
||||
NegZ
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor of the Direction Gizmo
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner of this object.</param>
|
||||
public DirectionGizmo(IGizmoOwner owner)
|
||||
{
|
||||
_owner = owner;
|
||||
_viewport = owner.Viewport;
|
||||
_viewportProjection.Init(owner.Viewport);
|
||||
|
||||
_xAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = false, Direction = AxisDirection.PosX };
|
||||
_yAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = false, Direction = AxisDirection.PosY };
|
||||
_zAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = false, Direction = AxisDirection.PosZ };
|
||||
|
||||
_negXAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = true, Direction = AxisDirection.NegX };
|
||||
_negYAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = true, Direction = AxisDirection.NegY };
|
||||
_negZAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = true, Direction = AxisDirection.NegZ };
|
||||
_axisData.EnsureCapacity(6);
|
||||
_spritePositions.EnsureCapacity(6);
|
||||
|
||||
_posHandle = Editor.Instance.Icons.VisjectBoxClosed32;
|
||||
_negHandle = Editor.Instance.Icons.VisjectBoxOpen32;
|
||||
|
||||
_fontReference = new FontReference(Style.Current.FontSmall);
|
||||
_fontReference.Size = 8;
|
||||
}
|
||||
|
||||
private bool IsPointInSprite(Float2 point, Float2 spriteCenter)
|
||||
{
|
||||
Float2 delta = point - spriteCenter;
|
||||
float distanceSq = delta.LengthSquared;
|
||||
float radiusSq = _spriteRadius * _spriteRadius;
|
||||
return distanceSq <= radiusSq;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
_hoveredAxisIndex = -1;
|
||||
|
||||
// Check which axis is being hovered - check from closest to farthest for proper layering
|
||||
for (int i = _spritePositions.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (IsPointInSprite(location, _spritePositions[i].position))
|
||||
{
|
||||
_hoveredAxisIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
|
||||
// Check which axis is being clicked - check from closest to farthest for proper layering
|
||||
for (int i = _spritePositions.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (IsPointInSprite(location, _spritePositions[i].position))
|
||||
{
|
||||
OrientViewToAxis(_spritePositions[i].direction);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OrientViewToAxis(AxisDirection direction)
|
||||
{
|
||||
Quaternion orientation = direction switch
|
||||
{
|
||||
AxisDirection.PosX => Quaternion.Euler(0, 90, 0),
|
||||
AxisDirection.NegX => Quaternion.Euler(0, -90, 0),
|
||||
AxisDirection.PosY => Quaternion.Euler(-90, 0, 0),
|
||||
AxisDirection.NegY => Quaternion.Euler(90, 0, 0),
|
||||
AxisDirection.PosZ => Quaternion.Euler(0, 0, 0),
|
||||
AxisDirection.NegZ => Quaternion.Euler(0, 180, 0),
|
||||
_ => Quaternion.Identity
|
||||
};
|
||||
_viewport.OrientViewport(ref orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to Draw the gizmo.
|
||||
/// </summary>
|
||||
public override void DrawSelf()
|
||||
{
|
||||
base.DrawSelf();
|
||||
|
||||
var features = Render2D.Features;
|
||||
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
|
||||
_viewportProjection.Init(_owner.Viewport);
|
||||
_gizmoCenter = _viewport.Task.View.WorldPosition + _viewport.Task.View.Direction * 1500;
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter, out var gizmoCenterScreen);
|
||||
|
||||
var relativeCenter = Size * 0.5f;
|
||||
|
||||
// Project unit vectors
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Right, out var xProjected);
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Up, out var yProjected);
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Forward, out var zProjected);
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Right, out var negXProjected);
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Up, out var negYProjected);
|
||||
_viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Forward, out var negZProjected);
|
||||
|
||||
// Normalize by viewport height to keep size independent of FOV and viewport dimensions
|
||||
float heightNormalization = _viewport.Height / 720.0f; // 720 = reference height
|
||||
if (_owner.Viewport.UseOrthographicProjection)
|
||||
heightNormalization /= _owner.Viewport.OrthographicScale * 0.5f; // Fix in ortho view to keep consistent size regardless of zoom level
|
||||
|
||||
Float2 xDelta = (xProjected - gizmoCenterScreen) / heightNormalization;
|
||||
Float2 yDelta = (yProjected - gizmoCenterScreen) / heightNormalization;
|
||||
Float2 zDelta = (zProjected - gizmoCenterScreen) / heightNormalization;
|
||||
Float2 negXDelta = (negXProjected - gizmoCenterScreen) / heightNormalization;
|
||||
Float2 negYDelta = (negYProjected - gizmoCenterScreen) / heightNormalization;
|
||||
Float2 negZDelta = (negZProjected - gizmoCenterScreen) / heightNormalization;
|
||||
|
||||
// Calculate distances from camera to determine draw order
|
||||
Vector3 cameraPosition = _viewport.Task.View.Position;
|
||||
float xDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Right);
|
||||
float yDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Up);
|
||||
float zDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Forward);
|
||||
float negXDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Right);
|
||||
float negYDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Up);
|
||||
float negZDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Forward);
|
||||
|
||||
_xAxisData.Delta = xDelta;
|
||||
_xAxisData.Distance = xDistance;
|
||||
_yAxisData.Delta = yDelta;
|
||||
_yAxisData.Distance = yDistance;
|
||||
_zAxisData.Delta = zDelta;
|
||||
_zAxisData.Distance = zDistance;
|
||||
_negXAxisData.Delta = negXDelta;
|
||||
_negXAxisData.Distance = negXDistance;
|
||||
_negYAxisData.Delta = negYDelta;
|
||||
_negYAxisData.Distance = negYDistance;
|
||||
_negZAxisData.Delta = negZDelta;
|
||||
_negZAxisData.Distance = negZDistance;
|
||||
|
||||
// Sort for correct draw order.
|
||||
_axisData.Clear();
|
||||
_axisData.AddRange([_xAxisData, _yAxisData, _zAxisData, _negXAxisData, _negYAxisData, _negZAxisData]);
|
||||
_axisData.Sort((a, b) => -a.Distance.CompareTo(b.Distance));
|
||||
|
||||
// Rebuild sprite positions list for hover detection
|
||||
_spritePositions.Clear();
|
||||
|
||||
Render2D.DrawSprite(_posHandle, new Rectangle(0, 0, Size), Color.Black.AlphaMultiplied(0.1f));
|
||||
|
||||
// Draw in order from farthest to closest
|
||||
for (int i = 0; i < _axisData.Count; i++)
|
||||
{
|
||||
var axis = _axisData[i];
|
||||
Float2 tipScreen = relativeCenter + axis.Delta * _axisLength;
|
||||
Float2 tipTextScreen = relativeCenter + axis.Delta * _textAxisLength;
|
||||
bool isHovered = _hoveredAxisIndex == i;
|
||||
|
||||
// Store sprite position for hover detection
|
||||
_spritePositions.Add((tipTextScreen, axis.Direction));
|
||||
|
||||
var axisColor = isHovered ? new Color(1.0f, 0.8980392f, 0.039215688f) : axis.AxisColor;
|
||||
var font = _fontReference.GetFont();
|
||||
if (!axis.Negative)
|
||||
{
|
||||
Render2D.DrawLine(relativeCenter, tipScreen, axisColor, 2.0f);
|
||||
Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axisColor);
|
||||
Render2D.DrawText(font, axis.Label, isHovered ? Color.Gray : Color.Black, tipTextScreen - font.MeasureText(axis.Label) * 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axisColor.RGBMultiplied(0.65f));
|
||||
Render2D.DrawSprite(_negHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axisColor);
|
||||
if (isHovered)
|
||||
Render2D.DrawText(font, axis.Label, Color.Black, tipTextScreen - font.MeasureText(axis.Label) * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
Render2D.Features = features;
|
||||
}
|
||||
}
|
||||
@@ -710,6 +710,10 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Node Editors"), EditorOrder(4580)]
|
||||
public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.A, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+F")]
|
||||
[EditorDisplay("Node Editors"), EditorOrder(4590)]
|
||||
public InputBinding FocusSelectedNodes = new InputBinding(KeyboardKeys.F, KeyboardKeys.Shift);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
29
Source/Editor/SceneGraph/Actors/RigidBodyNode.cs
Normal file
29
Source/Editor/SceneGraph/Actors/RigidBodyNode.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
/// <summary>
|
||||
/// Scene tree node for <see cref="RigidBody"/> actor type.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public sealed class RigidBodyNode : ActorNode
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public RigidBodyNode(Actor actor)
|
||||
: base(actor)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PostSpawn()
|
||||
{
|
||||
base.PostSpawn();
|
||||
|
||||
if (HasPrefabLink)
|
||||
return;
|
||||
Actor.StaticFlags = StaticFlags.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,13 +324,12 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id);
|
||||
}
|
||||
|
||||
if (isExpanded)
|
||||
if (!noFilter)
|
||||
{
|
||||
Expand(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Collapse(true);
|
||||
if (isExpanded)
|
||||
Expand(true);
|
||||
else
|
||||
Collapse(true);
|
||||
}
|
||||
|
||||
Visible = isThisVisible | isAnyChildVisible;
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace FlaxEditor.SceneGraph
|
||||
CustomNodesTypes.Add(typeof(NavMesh), typeof(ActorNode));
|
||||
CustomNodesTypes.Add(typeof(SpriteRender), typeof(SpriteRenderNode));
|
||||
CustomNodesTypes.Add(typeof(Joint), typeof(JointNode));
|
||||
CustomNodesTypes.Add(typeof(RigidBody), typeof(RigidBodyNode));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
// [Deprecated]
|
||||
TypeID = 3,
|
||||
Title = "Pack Material Layer",
|
||||
Description = "Pack material properties",
|
||||
@@ -75,6 +76,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
// [Deprecated]
|
||||
TypeID = 4,
|
||||
Title = "Unpack Material Layer",
|
||||
Description = "Unpack material properties",
|
||||
@@ -120,6 +122,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 6,
|
||||
Title = "Pack Material Layer",
|
||||
Description = "Pack material properties",
|
||||
AlternativeTitles = new[] { "Make Material Layer", "Construct Material Layer", "Compose Material Layer" },
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(200, 280),
|
||||
Elements = new[]
|
||||
@@ -146,6 +149,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 7,
|
||||
Title = "Unpack Material Layer",
|
||||
Description = "Unpack material properties",
|
||||
AlternativeTitles = new[] { "Break Material Layer", "Deconstruct Material Layer", "Decompose Material Layer", "Split Material Layer" },
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(210, 280),
|
||||
Elements = new[]
|
||||
|
||||
@@ -342,6 +342,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 20,
|
||||
Title = "Pack Float2",
|
||||
Description = "Pack components to Float2",
|
||||
AlternativeTitles = new[] { "Make Float2", "Construct Float2", "Compose Float2" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 40),
|
||||
DefaultValues = new object[]
|
||||
@@ -361,6 +362,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 21,
|
||||
Title = "Pack Float3",
|
||||
Description = "Pack components to Float3",
|
||||
AlternativeTitles = new[] { "Make Float3", "Construct Float3", "Compose Float3" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 60),
|
||||
DefaultValues = new object[]
|
||||
@@ -382,6 +384,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 22,
|
||||
Title = "Pack Float4",
|
||||
Description = "Pack components to Float4",
|
||||
AlternativeTitles = new[] { "Make Float4", "Construct Float4", "Compose Float4" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 80),
|
||||
DefaultValues = new object[]
|
||||
@@ -405,6 +408,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 23,
|
||||
Title = "Pack Rotation",
|
||||
Description = "Pack components to Rotation",
|
||||
AlternativeTitles = new[] { "Make Rotation", "Construct Rotation", "Compose Rotation" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 60),
|
||||
DefaultValues = new object[]
|
||||
@@ -426,6 +430,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 24,
|
||||
Title = "Pack Transform",
|
||||
Description = "Pack components to Transform",
|
||||
AlternativeTitles = new[] { "Make Transform", "Construct Transform", "Compose Transform" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 80),
|
||||
Elements = new[]
|
||||
@@ -441,6 +446,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 25,
|
||||
Title = "Pack Box",
|
||||
Description = "Pack components to BoundingBox",
|
||||
AlternativeTitles = new[] { "Make Box", "Construct Box", "Compose Box" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 40),
|
||||
Elements = new[]
|
||||
@@ -454,6 +460,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 26,
|
||||
Title = "Pack Structure",
|
||||
AlternativeTitles = new[] { "Make Structure", "Construct Structure", "Compose Structure" },
|
||||
Create = (id, context, arch, groupArch) => new PackStructureNode(id, context, arch, groupArch),
|
||||
IsInputCompatible = PackStructureNode.IsInputCompatible,
|
||||
IsOutputCompatible = PackStructureNode.IsOutputCompatible,
|
||||
@@ -479,6 +486,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 30,
|
||||
Title = "Unpack Float2",
|
||||
Description = "Unpack components from Float2",
|
||||
AlternativeTitles = new[] { "Break Float2", "Deconstruct Float2", "Decompose Float2", "Split Float2" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 40),
|
||||
Elements = new[]
|
||||
@@ -493,6 +501,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 31,
|
||||
Title = "Unpack Float3",
|
||||
Description = "Unpack components from Float3",
|
||||
AlternativeTitles = new[] { "Break Float3", "Deconstruct Float3", "Decompose Float3", "Split Float3" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 60),
|
||||
Elements = new[]
|
||||
@@ -508,6 +517,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 32,
|
||||
Title = "Unpack Float4",
|
||||
Description = "Unpack components from Float4",
|
||||
AlternativeTitles = new[] { "Break Float4", "Deconstruct Float4", "Decompose Float4", "Split Float4" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(150, 80),
|
||||
Elements = new[]
|
||||
@@ -524,6 +534,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 33,
|
||||
Title = "Unpack Rotation",
|
||||
Description = "Unpack components from Rotation",
|
||||
AlternativeTitles = new[] { "Break Rotation", "Deconstruct Rotation", "Decompose Rotation", "Split Rotation" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(170, 60),
|
||||
Elements = new[]
|
||||
@@ -539,6 +550,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 34,
|
||||
Title = "Unpack Transform",
|
||||
Description = "Unpack components from Transform",
|
||||
AlternativeTitles = new[] { "Break Transform", "Deconstruct Transform", "Decompose Transform", "Split Transform" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(170, 60),
|
||||
Elements = new[]
|
||||
@@ -554,6 +566,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
TypeID = 35,
|
||||
Title = "Unpack Box",
|
||||
Description = "Unpack components from BoundingBox",
|
||||
AlternativeTitles = new[] { "Break BoundingBox", "Deconstruct BoundingBox", "Decompose BoundingBox", "Split BoundingBox" },
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(170, 40),
|
||||
Elements = new[]
|
||||
@@ -572,6 +585,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
IsOutputCompatible = UnpackStructureNode.IsOutputCompatible,
|
||||
GetInputOutputDescription = UnpackStructureNode.GetInputOutputDescription,
|
||||
Description = "Breaks the structure data to allow extracting components from it.",
|
||||
AlternativeTitles = new[] { "Break Structure", "Deconstruct Structure", "Decompose Structure", "Split Structure" },
|
||||
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI,
|
||||
Size = new Float2(180, 20),
|
||||
DefaultValues = new object[]
|
||||
|
||||
@@ -585,7 +585,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
|
||||
private void UpdateFilters()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes[0] == null)
|
||||
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes.Count == 0)
|
||||
{
|
||||
ResetView();
|
||||
Profiler.EndEvent();
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -574,13 +574,13 @@ namespace FlaxEditor.Surface
|
||||
var showSearch = () => editor.ContentFinding.ShowSearch(window);
|
||||
|
||||
// Toolstrip
|
||||
saveButton = toolStrip.AddButton(editor.Icons.Save64, window.Save).LinkTooltip("Save", ref inputOptions.Save);
|
||||
saveButton = toolStrip.AddButton(editor.Icons.Save64, window.Save).LinkTooltip("Save.", ref inputOptions.Save);
|
||||
toolStrip.AddSeparator();
|
||||
undoButton = toolStrip.AddButton(editor.Icons.Undo64, undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
|
||||
redoButton = toolStrip.AddButton(editor.Icons.Redo64, undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
|
||||
undoButton = toolStrip.AddButton(editor.Icons.Undo64, undo.PerformUndo).LinkTooltip("Undo.", ref inputOptions.Undo);
|
||||
redoButton = toolStrip.AddButton(editor.Icons.Redo64, undo.PerformRedo).LinkTooltip("Redo.", ref inputOptions.Redo);
|
||||
toolStrip.AddSeparator();
|
||||
toolStrip.AddButton(editor.Icons.Search64, showSearch).LinkTooltip("Open content search tool", ref inputOptions.Search);
|
||||
toolStrip.AddButton(editor.Icons.CenterView64, surface.ShowWholeGraph).LinkTooltip("Show whole graph");
|
||||
toolStrip.AddButton(editor.Icons.Search64, showSearch).LinkTooltip("Open content search tool.", ref inputOptions.Search);
|
||||
toolStrip.AddButton(editor.Icons.CenterView64, surface.ShowWholeGraph).LinkTooltip("Show whole graph.");
|
||||
var gridSnapButton = toolStrip.AddButton(editor.Icons.Grid32, surface.ToggleGridSnapping);
|
||||
gridSnapButton.LinkTooltip("Toggle grid snapping for nodes.");
|
||||
gridSnapButton.AutoCheck = true;
|
||||
|
||||
@@ -410,8 +410,11 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
menu.AddSeparator();
|
||||
|
||||
_cmFormatNodesMenu = menu.AddChildMenu("Format node(s)");
|
||||
_cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection;
|
||||
bool allNodesNoMove = SelectedNodes.All(n => n.Archetype.Flags.HasFlag(NodeFlags.NoMove));
|
||||
bool clickedNodeNoMove = ((SelectedNodes.Count == 1 && controlUnderMouse is SurfaceNode n && n.Archetype.Flags.HasFlag(NodeFlags.NoMove)));
|
||||
|
||||
_cmFormatNodesMenu = menu.AddChildMenu("Format nodes");
|
||||
_cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection && !(allNodesNoMove || clickedNodeNoMove);
|
||||
|
||||
_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); });
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace FlaxEditor.Surface
|
||||
if (nodes.Count <= 1)
|
||||
return;
|
||||
|
||||
List<MoveNodesAction> undoActions = new List<MoveNodesAction>();
|
||||
|
||||
var nodesToVisit = new HashSet<SurfaceNode>(nodes);
|
||||
|
||||
// While we haven't formatted every node
|
||||
@@ -73,18 +75,23 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
FormatConnectedGraph(connectedNodes);
|
||||
undoActions.AddRange(FormatConnectedGraph(connectedNodes));
|
||||
}
|
||||
|
||||
Undo?.AddAction(new MultiUndoAction(undoActions, "Format nodes"));
|
||||
MarkAsEdited(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a graph where all nodes are connected.
|
||||
/// </summary>
|
||||
/// <param name="nodes">List of connected nodes.</param>
|
||||
protected void FormatConnectedGraph(List<SurfaceNode> nodes)
|
||||
private List<MoveNodesAction> FormatConnectedGraph(List<SurfaceNode> nodes)
|
||||
{
|
||||
List<MoveNodesAction> undoActions = new List<MoveNodesAction>();
|
||||
|
||||
if (nodes.Count <= 1)
|
||||
return;
|
||||
return undoActions;
|
||||
|
||||
var boundingBox = GetNodesBounds(nodes);
|
||||
|
||||
@@ -140,7 +147,6 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
// Set the node positions
|
||||
var undoActions = new List<MoveNodesAction>();
|
||||
var topRightPosition = endNodes[0].Location;
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
@@ -155,16 +161,18 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
MarkAsEdited(false);
|
||||
Undo?.AddAction(new MultiUndoAction(undoActions, "Format nodes"));
|
||||
return undoActions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Straightens every connection between nodes in <paramref name="nodes"/>.
|
||||
/// </summary>
|
||||
/// <param name="nodes">List of nodes.</param>
|
||||
/// <returns>List of undo actions.</returns>
|
||||
public void StraightenGraphConnections(List<SurfaceNode> nodes)
|
||||
{
|
||||
{
|
||||
nodes = nodes.Where(n => !n.Archetype.Flags.HasFlag(NodeFlags.NoMove)).ToList();
|
||||
|
||||
if (nodes.Count <= 1)
|
||||
return;
|
||||
|
||||
@@ -350,8 +358,10 @@ namespace FlaxEditor.Surface
|
||||
/// <param name="nodes">List of nodes.</param>
|
||||
/// <param name="alignmentType">Alignemnt type.</param>
|
||||
public void AlignNodes(List<SurfaceNode> nodes, NodeAlignmentType alignmentType)
|
||||
{
|
||||
if(nodes.Count <= 1)
|
||||
{
|
||||
nodes = nodes.Where(n => !n.Archetype.Flags.HasFlag(NodeFlags.NoMove)).ToList();
|
||||
|
||||
if (nodes.Count <= 1)
|
||||
return;
|
||||
|
||||
var undoActions = new List<MoveNodesAction>();
|
||||
@@ -392,6 +402,8 @@ namespace FlaxEditor.Surface
|
||||
/// <param name="vertically">If false will be done horizontally, if true will be done vertically.</param>
|
||||
public void DistributeNodes(List<SurfaceNode> nodes, bool vertically)
|
||||
{
|
||||
nodes = nodes.Where(n => !n.Archetype.Flags.HasFlag(NodeFlags.NoMove)).ToList();
|
||||
|
||||
if(nodes.Count <= 1)
|
||||
return;
|
||||
|
||||
|
||||
@@ -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,26 @@ 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
|
||||
{
|
||||
@@ -250,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;
|
||||
@@ -321,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;
|
||||
@@ -420,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)
|
||||
{
|
||||
@@ -515,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))
|
||||
{
|
||||
@@ -554,6 +607,9 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_isLazyConnecting && Nodes.Count > 0)
|
||||
_lazyConnectStartNode = GetClosestNodeAtLocation(location);
|
||||
|
||||
// Cache flags and state
|
||||
if (_leftMouseDown)
|
||||
{
|
||||
@@ -602,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;
|
||||
@@ -630,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)
|
||||
{
|
||||
@@ -651,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);
|
||||
@@ -704,13 +847,21 @@ namespace FlaxEditor.Surface
|
||||
|
||||
private void MoveSelectedNodes(Float2 delta)
|
||||
{
|
||||
// TODO: undo
|
||||
List<MoveNodesAction> undoActions = new List<MoveNodesAction>();
|
||||
|
||||
delta /= _targetScale;
|
||||
OnGetNodesToMove();
|
||||
foreach (var node in _movingNodes)
|
||||
{
|
||||
node.Location += delta;
|
||||
if (Undo != null)
|
||||
undoActions.Add(new MoveNodesAction(Context, new[] { node.ID }, delta));
|
||||
}
|
||||
_isMovingSelection = false;
|
||||
MarkAsEdited(false);
|
||||
|
||||
if (undoActions.Count > 0)
|
||||
Undo?.AddAction(new MultiUndoAction(undoActions, "Moved "));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -837,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 = "";
|
||||
@@ -845,7 +1019,8 @@ namespace FlaxEditor.Surface
|
||||
|
||||
private void CurrentInputTextChanged(string currentInputText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentInputText))
|
||||
// Check if focus selected nodes binding is being pressed to prevent it triggering primary menu
|
||||
if (string.IsNullOrEmpty(currentInputText) || _focusSelectedNodeBinding.Process(RootWindow))
|
||||
return;
|
||||
if (IsPrimaryMenuOpened || !CanEdit)
|
||||
{
|
||||
@@ -1025,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++)
|
||||
{
|
||||
@@ -1035,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;
|
||||
|
||||
@@ -423,8 +423,9 @@ namespace FlaxEditor.Surface
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }),
|
||||
new InputActionsContainer.Binding(options => options.FocusSelectedNodes, () => { FocusSelectionOrWholeGraph(); }),
|
||||
});
|
||||
|
||||
Context.ControlSpawned += OnSurfaceControlSpawned;
|
||||
@@ -436,7 +437,10 @@ namespace FlaxEditor.Surface
|
||||
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
|
||||
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
|
||||
|
||||
OnEditorOptionsChanged(Editor.Instance.Options.Options);
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
@@ -446,6 +450,11 @@ namespace FlaxEditor.Surface
|
||||
_cmPrimaryMenu = null;
|
||||
}
|
||||
|
||||
private void OnEditorOptionsChanged(EditorOptions options)
|
||||
{
|
||||
_focusSelectedNodeBinding = options.Input.FocusSelectedNodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display name of the connection type used in the surface.
|
||||
/// </summary>
|
||||
@@ -648,6 +657,37 @@ namespace FlaxEditor.Surface
|
||||
ViewCenterPosition = areaRect.Center;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the view to focus on the currently selected nodes, or the entire graph if no nodes are selected.
|
||||
/// </summary>
|
||||
public void FocusSelectionOrWholeGraph()
|
||||
{
|
||||
if (SelectedNodes.Count > 0)
|
||||
ShowSelection();
|
||||
else
|
||||
ShowWholeGraph();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the selected controls by changing the view scale and the position.
|
||||
/// </summary>
|
||||
public void ShowSelection()
|
||||
{
|
||||
var selection = SelectedControls;
|
||||
if (selection.Count == 0)
|
||||
return;
|
||||
|
||||
// Calculate the bounds of all selected controls
|
||||
Rectangle bounds = selection[0].Bounds;
|
||||
for (int i = 1; i < selection.Count; i++)
|
||||
bounds = Rectangle.Union(bounds, selection[i].Bounds);
|
||||
|
||||
// Add margin
|
||||
bounds = bounds.MakeExpanded(250.0f);
|
||||
|
||||
ShowArea(bounds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the given surface node by changing the view scale and the position and focuses the node.
|
||||
/// </summary>
|
||||
@@ -1071,6 +1111,7 @@ namespace FlaxEditor.Surface
|
||||
_cmPrimaryMenu?.Dispose();
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace FlaxEditor.Tools.Terrain
|
||||
if (!terrain.HasPatch(ref patchCoord) && _planeModel)
|
||||
{
|
||||
var planeSize = 100.0f;
|
||||
var patchSize = terrain.ChunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
|
||||
var patchSize = terrain.PatchSize;
|
||||
Matrix world = Matrix.RotationX(-Mathf.PiOverTwo) *
|
||||
Matrix.Scaling(patchSize / planeSize) *
|
||||
Matrix.Translation(patchSize * (0.5f + patchCoord.X), 0, patchSize * (0.5f + patchCoord.Y)) *
|
||||
|
||||
@@ -69,9 +69,9 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
var splatmapIndex = ActiveSplatmapIndex;
|
||||
var splatmapIndexOther = (splatmapIndex + 1) % 2;
|
||||
var chunkSize = terrain.ChunkSize;
|
||||
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
|
||||
var heightmapSize = terrain.HeightmapSize;
|
||||
var heightmapLength = heightmapSize * heightmapSize;
|
||||
var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
|
||||
var patchSize = terrain.PatchSize;
|
||||
var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, splatmapIndex).ToPointer();
|
||||
var tempBufferOther = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, (splatmapIndex + 1) % 2).ToPointer();
|
||||
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;
|
||||
|
||||
@@ -70,9 +70,9 @@ namespace FlaxEditor.Tools.Terrain.Sculpt
|
||||
|
||||
// Prepare
|
||||
var chunkSize = terrain.ChunkSize;
|
||||
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
|
||||
var heightmapSize = terrain.HeightmapSize;
|
||||
var heightmapLength = heightmapSize * heightmapSize;
|
||||
var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
|
||||
var patchSize = terrain.PatchSize;
|
||||
var tempBuffer = (float*)gizmo.GetHeightmapTempBuffer(heightmapLength * sizeof(float)).ToPointer();
|
||||
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;
|
||||
|
||||
|
||||
@@ -382,7 +382,8 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
|
||||
const Int2 heightmapSize = size * Terrain::ChunksCountEdge * terrain->GetChunkSize() + 1;
|
||||
Array<float> heightmap;
|
||||
heightmap.Resize(heightmapSize.X * heightmapSize.Y);
|
||||
heightmap.SetAll(firstPatch->GetHeightmapData()[0]);
|
||||
if (const float* heightmapData = firstPatch->GetHeightmapData())
|
||||
heightmap.SetAll(heightmapData[0]);
|
||||
|
||||
// Fill heightmap with data from all patches
|
||||
const int32 rowSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
|
||||
@@ -392,8 +393,16 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
|
||||
const Int2 pos(patch->GetX() - start.X, patch->GetZ() - start.Y);
|
||||
const float* src = patch->GetHeightmapData();
|
||||
float* dst = heightmap.Get() + pos.X * (rowSize - 1) + pos.Y * heightmapSize.X * (rowSize - 1);
|
||||
for (int32 row = 0; row < rowSize; row++)
|
||||
Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float));
|
||||
if (src)
|
||||
{
|
||||
for (int32 row = 0; row < rowSize; row++)
|
||||
Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 row = 0; row < rowSize; row++)
|
||||
Platform::MemoryClear(dst + row * heightmapSize.X, rowSize * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate to 16-bit int
|
||||
|
||||
@@ -85,8 +85,7 @@ namespace FlaxEditor.Tools.Terrain.Undo
|
||||
{
|
||||
_terrain = terrain.ID;
|
||||
_patches = new List<PatchData>(4);
|
||||
var chunkSize = terrain.ChunkSize;
|
||||
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
|
||||
var heightmapSize = terrain.HeightmapSize;
|
||||
_heightmapLength = heightmapSize * heightmapSize;
|
||||
_heightmapDataSize = _heightmapLength * stride;
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@ namespace FlaxEditor.Viewport
|
||||
/// Orients the viewport.
|
||||
/// </summary>
|
||||
/// <param name="orientation">The orientation.</param>
|
||||
protected void OrientViewport(Quaternion orientation)
|
||||
public void OrientViewport(Quaternion orientation)
|
||||
{
|
||||
OrientViewport(ref orientation);
|
||||
}
|
||||
@@ -1238,7 +1238,7 @@ namespace FlaxEditor.Viewport
|
||||
/// Orients the viewport.
|
||||
/// </summary>
|
||||
/// <param name="orientation">The orientation.</param>
|
||||
protected virtual void OrientViewport(ref Quaternion orientation)
|
||||
public virtual void OrientViewport(ref Quaternion orientation)
|
||||
{
|
||||
if (ViewportCamera is FPSCamera fpsCamera)
|
||||
{
|
||||
|
||||
@@ -108,13 +108,14 @@ namespace FlaxEditor.Viewport
|
||||
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
|
||||
private EditorSpritesRenderer _editorSpritesRenderer;
|
||||
private ViewportRubberBandSelector _rubberBandSelector;
|
||||
private DirectionGizmo _directionGizmo;
|
||||
|
||||
private bool _gameViewActive;
|
||||
private ViewFlags _preGameViewFlags;
|
||||
private ViewMode _preGameViewViewMode;
|
||||
private bool _gameViewWasGridShown;
|
||||
private bool _gameViewWasFpsCounterShown;
|
||||
private bool _gameViewWasNagivationShown;
|
||||
private bool _gameViewWasNavigationShown;
|
||||
|
||||
/// <summary>
|
||||
/// Drag and drop handlers
|
||||
@@ -225,6 +226,12 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
// Add rubber band selector
|
||||
_rubberBandSelector = new ViewportRubberBandSelector(this);
|
||||
_directionGizmo = new DirectionGizmo(this);
|
||||
_directionGizmo.AnchorPreset = AnchorPresets.TopRight;
|
||||
_directionGizmo.Parent = this;
|
||||
_directionGizmo.LocalY += 25;
|
||||
_directionGizmo.LocalX -= 150;
|
||||
_directionGizmo.Size = new Float2(150, 150);
|
||||
|
||||
// Add grid
|
||||
Grid = new GridGizmo(this);
|
||||
@@ -244,6 +251,12 @@ namespace FlaxEditor.Viewport
|
||||
_showNavigationButton = ViewWidgetShowMenu.AddButton("Navigation", inputOptions.ToggleNavMeshVisibility, () => ShowNavigation = !ShowNavigation);
|
||||
_showNavigationButton.CloseMenuOnClick = false;
|
||||
|
||||
// Show direction gizmo widget
|
||||
var showDirectionGizmoButton = ViewWidgetShowMenu.AddButton("Direction Gizmo", () => _directionGizmo.Visible = !_directionGizmo.Visible);
|
||||
showDirectionGizmoButton.AutoCheck = true;
|
||||
showDirectionGizmoButton.CloseMenuOnClick = false;
|
||||
showDirectionGizmoButton.Checked = _directionGizmo.Visible;
|
||||
|
||||
// Game View
|
||||
ViewWidgetButtonMenu.AddSeparator();
|
||||
_toggleGameViewButton = ViewWidgetButtonMenu.AddButton("Game View", inputOptions.ToggleGameView, ToggleGameView);
|
||||
@@ -514,14 +527,14 @@ namespace FlaxEditor.Viewport
|
||||
_preGameViewViewMode = Task.ViewMode;
|
||||
_gameViewWasGridShown = Grid.Enabled;
|
||||
_gameViewWasFpsCounterShown = ShowFpsCounter;
|
||||
_gameViewWasNagivationShown = ShowNavigation;
|
||||
_gameViewWasNavigationShown = ShowNavigation;
|
||||
}
|
||||
|
||||
// Set flags & values
|
||||
Task.ViewFlags = _gameViewActive ? _preGameViewFlags : ViewFlags.DefaultGame;
|
||||
Task.ViewMode = _gameViewActive ? _preGameViewViewMode : ViewMode.Default;
|
||||
ShowFpsCounter = _gameViewActive ? _gameViewWasFpsCounterShown : false;
|
||||
ShowNavigation = _gameViewActive ? _gameViewWasNagivationShown : false;
|
||||
ShowNavigation = _gameViewActive ? _gameViewWasNavigationShown : false;
|
||||
Grid.Enabled = _gameViewActive ? _gameViewWasGridShown : false;
|
||||
|
||||
_gameViewActive = !_gameViewActive;
|
||||
@@ -647,7 +660,7 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OrientViewport(ref Quaternion orientation)
|
||||
public override void OrientViewport(ref Quaternion orientation)
|
||||
{
|
||||
if (TransformGizmo.SelectedParents.Count != 0)
|
||||
FocusSelection(ref orientation);
|
||||
|
||||
@@ -681,7 +681,7 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OrientViewport(ref Quaternion orientation)
|
||||
public override void OrientViewport(ref Quaternion orientation)
|
||||
{
|
||||
if (TransformGizmo.SelectedParents.Count != 0)
|
||||
FocusSelection(ref orientation);
|
||||
|
||||
@@ -303,8 +303,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
_terrain = new Terrain();
|
||||
_terrain.Setup(1, 63);
|
||||
var chunkSize = _terrain.ChunkSize;
|
||||
var heightMapSize = chunkSize * Terrain.PatchEdgeChunksCount + 1;
|
||||
var heightMapSize = _terrain.HeightmapSize;
|
||||
var heightMapLength = heightMapSize * heightMapSize;
|
||||
var heightmap = new float[heightMapLength];
|
||||
var patchCoord = new Int2(0, 0);
|
||||
|
||||
@@ -431,6 +431,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
_isWaitingForTimelineLoad = true;
|
||||
|
||||
base.OnItemReimported(item);
|
||||
|
||||
// Drop virtual asset state and get a new one from the reimported file
|
||||
LoadFromOriginal();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
Parent = this
|
||||
};
|
||||
_toolstrip.AddButton(editor.Icons.Search64, () => Editor.Windows.ContentWin.Select(_item)).LinkTooltip("Show and select in Content Window");
|
||||
_toolstrip.AddButton(editor.Icons.Search64, () => Editor.Windows.ContentWin.Select(_item)).LinkTooltip("Show and select in Content Window.");
|
||||
|
||||
InputActions.Add(options => options.Save, Save);
|
||||
|
||||
@@ -527,6 +527,16 @@ namespace FlaxEditor.Windows.Assets
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the asset from the original location to reflect the state (eg. after original asset reimport).
|
||||
/// </summary>
|
||||
protected virtual void LoadFromOriginal()
|
||||
{
|
||||
_asset = LoadAsset();
|
||||
OnAssetLoaded();
|
||||
ClearEditedFlag();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override T LoadAsset()
|
||||
{
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace FlaxEditor.Windows
|
||||
|
||||
var root = _root;
|
||||
root.LockChildrenRecursive();
|
||||
PerformLayout();
|
||||
|
||||
// Update tree
|
||||
var query = _foldersSearchBox.Text;
|
||||
|
||||
@@ -1126,6 +1126,8 @@ namespace FlaxEditor.Windows
|
||||
if (Editor.ContentDatabase.Find(_lastViewedFolderBeforeReload) is ContentFolder folder)
|
||||
_tree.Select(folder.Node);
|
||||
}
|
||||
|
||||
OnFoldersSearchBoxTextChanged();
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace FlaxEditor.Windows
|
||||
TooltipText = "Search the scene tree.\n\nYou can prefix your search with different search operators:\ns: -> Actor with script of type\na: -> Actor type\nc: -> Control type",
|
||||
};
|
||||
_searchBox.TextChanged += OnSearchBoxTextChanged;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnSearchBoxTextChanged;
|
||||
|
||||
// Scene tree panel
|
||||
_sceneTreePanel = new Panel
|
||||
@@ -111,7 +112,7 @@ namespace FlaxEditor.Windows
|
||||
InputActions.Add(options => options.LockFocusSelection, () => Editor.Windows.EditWin.Viewport.LockFocusSelection());
|
||||
InputActions.Add(options => options.Rename, RenameSelection);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayBeginning()
|
||||
{
|
||||
@@ -124,6 +125,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
base.OnPlayBegin();
|
||||
_blockSceneTreeScroll = false;
|
||||
OnSearchBoxTextChanged();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -138,6 +140,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
base.OnPlayEnd();
|
||||
_blockSceneTreeScroll = true;
|
||||
OnSearchBoxTextChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -173,6 +176,7 @@ namespace FlaxEditor.Windows
|
||||
return;
|
||||
|
||||
_tree.LockChildrenRecursive();
|
||||
PerformLayout();
|
||||
|
||||
// Update tree
|
||||
var query = _searchBox.Text;
|
||||
@@ -586,6 +590,7 @@ namespace FlaxEditor.Windows
|
||||
_dragHandlers = null;
|
||||
_tree = null;
|
||||
_searchBox = null;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnSearchBoxTextChanged;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user