Merge branch 'master' into 1.5

# Conflicts:
#	Source/Engine/Serialization/Stream.cpp
This commit is contained in:
Wojtek Figat
2022-11-21 15:51:57 +01:00
62 changed files with 391 additions and 351 deletions

View File

@@ -9,6 +9,8 @@ using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Scripting;
using FlaxEditor.Utilities;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
using Object = FlaxEngine.Object;
@@ -266,7 +268,7 @@ namespace FlaxEditor.SceneGraph.GUI
/// <summary>
/// Starts the actor renaming action.
/// </summary>
public void StartRenaming()
public void StartRenaming(EditorWindow window)
{
// Block renaming during scripts reload
if (Editor.Instance.ProgressReporting.CompileScripts.IsActive)
@@ -274,16 +276,22 @@ namespace FlaxEditor.SceneGraph.GUI
Select();
// Disable scrolling of scene view
Editor.Instance.Windows.SceneWin.ScrollingOnSceneTreeView(false);
// Disable scrolling of view
if (window is SceneTreeWindow)
(window as SceneTreeWindow).ScrollingOnSceneTreeView(false);
else if (window is PrefabWindow)
(window as PrefabWindow).ScrollingOnTreeView(false);
// Start renaming the actor
var dialog = RenamePopup.Show(this, HeaderRect, _actorNode.Name, false);
dialog.Renamed += OnRenamed;
dialog.Closed += popup =>
{
// Enable scrolling of scene view
Editor.Instance.Windows.SceneWin.ScrollingOnSceneTreeView(true);
// Enable scrolling of view
if (window is SceneTreeWindow)
(window as SceneTreeWindow).ScrollingOnSceneTreeView(true);
else if (window is PrefabWindow)
(window as PrefabWindow).ScrollingOnTreeView(true);
};
}
@@ -291,9 +299,6 @@ namespace FlaxEditor.SceneGraph.GUI
{
using (new UndoBlock(ActorNode.Root.Undo, Actor, "Rename"))
Actor.Name = renamePopup.Text;
// Enable scrolling of scene view
Editor.Instance.Windows.SceneWin.ScrollingOnSceneTreeView(true);
}
/// <inheritdoc />

View File

@@ -153,6 +153,9 @@ namespace FlaxEditor.Windows.Assets
{
OnPasteAction(pasteAction);
}
// Scroll to new selected node
ScrollToSelectedNode();
}
/// <summary>
@@ -180,6 +183,9 @@ namespace FlaxEditor.Windows.Assets
{
OnPasteAction(pasteAction);
}
// Scroll to new selected node
ScrollToSelectedNode();
}
private void OnPasteAction(PasteActorsAction pasteAction)
@@ -328,6 +334,9 @@ namespace FlaxEditor.Windows.Assets
}, action2.ActionString);
action.Do();
Undo.AddAction(action);
_treePanel.PerformLayout();
_treePanel.PerformLayout();
}
}
}

View File

@@ -67,7 +67,7 @@ namespace FlaxEditor.Windows.Assets
private DragHandlers _dragHandlers;
public SceneTreePanel(PrefabWindow window)
: base(ScrollBars.Vertical)
: base(ScrollBars.None)
{
_window = window;
Offsets = Margin.Zero;
@@ -246,24 +246,53 @@ namespace FlaxEditor.Windows.Assets
// Spawning actors options
contextMenu.AddSeparator();
var spawnMenu = contextMenu.AddChildMenu("New");
var newActorCm = spawnMenu.ContextMenu;
for (int i = 0; i < SceneTreeWindow.SpawnActorsGroups.Length; i++)
{
var group = SceneTreeWindow.SpawnActorsGroups[i];
if (group.Types.Length == 1)
// Go through each actor and add it to the context menu if it has the ActorContextMenu attribute
foreach (var actorType in Editor.CodeEditing.Actors.Get())
{
if (actorType.IsAbstract)
continue;
ActorContextMenuAttribute attribute = null;
foreach (var e in actorType.GetAttributes(true))
{
var type = group.Types[0].Value;
newActorCm.AddButton(group.Types[0].Key, () => Spawn(type));
}
else
{
var groupCm = newActorCm.AddChildMenu(group.Name).ContextMenu;
for (int j = 0; j < group.Types.Length; j++)
if (e is ActorContextMenuAttribute actorContextMenuAttribute)
{
var type = group.Types[j].Value;
groupCm.AddButton(group.Types[j].Key, () => Spawn(type));
attribute = actorContextMenuAttribute;
break;
}
}
if (attribute == null)
continue;
var splitPath = attribute.Path.Split('/');
ContextMenuChildMenu childCM = null;
bool mainCM = true;
for (int i = 0; i < splitPath?.Length; i++)
{
if (i == splitPath.Length - 1)
{
if (mainCM)
{
contextMenu.AddButton(splitPath[i].Trim(), () => Spawn(actorType.Type));
mainCM = false;
}
else
{
childCM?.ContextMenu.AddButton(splitPath[i].Trim(), () => Spawn(actorType.Type));
childCM.ContextMenu.AutoSort = true;
}
}
else
{
if (mainCM)
{
childCM = contextMenu.GetOrAddChildMenu(splitPath[i].Trim());
mainCM = false;
}
else
{
childCM = childCM?.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim());
}
childCM.ContextMenu.AutoSort = true;
}
}
}
@@ -310,7 +339,7 @@ namespace FlaxEditor.Windows.Assets
{
if (selection.Count != 0)
Select(actor);
actor.TreeNode.StartRenaming();
actor.TreeNode.StartRenaming(this);
}
}

View File

@@ -23,6 +23,7 @@ namespace FlaxEditor.Windows.Assets
private readonly SplitPanel _split1;
private readonly SplitPanel _split2;
private readonly TextBox _searchBox;
private readonly Panel _treePanel;
private readonly PrefabTree _tree;
private readonly PrefabWindowViewport _viewport;
private readonly CustomEditorPresenter _propertiesEditor;
@@ -132,17 +133,26 @@ namespace FlaxEditor.Windows.Assets
};
_searchBox.TextChanged += OnSearchBoxTextChanged;
_treePanel = new Panel()
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0.0f, 0.0f, headerPanel.Bottom, 0.0f),
ScrollBars = ScrollBars.Both,
IsScrollable = true,
Parent = sceneTreePanel,
};
// Prefab structure tree
Graph = new LocalSceneGraph(new CustomRootNode(this));
_tree = new PrefabTree
{
Y = headerPanel.Bottom,
Margin = new Margin(0.0f, 0.0f, -16.0f, 0.0f), // Hide root node
IsScrollable = true,
};
_tree.AddChild(Graph.Root.TreeNode);
_tree.SelectedChanged += OnTreeSelectedChanged;
_tree.RightClick += OnTreeRightClick;
_tree.Parent = sceneTreePanel;
_tree.Parent = _treePanel;
headerPanel.Parent = sceneTreePanel;
// Prefab viewport
@@ -192,6 +202,32 @@ namespace FlaxEditor.Windows.Assets
InputActions.Add(options => options.Rename, Rename);
InputActions.Add(options => options.FocusSelection, _viewport.FocusSelection);
}
/// <summary>
/// Enables or disables vertical and horizontal scrolling on the tree panel.
/// </summary>
/// <param name="enabled">The state to set scrolling to</param>
public void ScrollingOnTreeView(bool enabled)
{
if (_treePanel.VScrollBar != null)
_treePanel.VScrollBar.ThumbEnabled = enabled;
if (_treePanel.HScrollBar != null)
_treePanel.HScrollBar.ThumbEnabled = enabled;
}
/// <summary>
/// Scrolls to the selected node in the tree.
/// </summary>
public void ScrollToSelectedNode()
{
// Scroll to node
var nodeSelection = _tree.Selection;
if (nodeSelection.Count != 0)
{
var scrollControl = nodeSelection[nodeSelection.Count - 1];
_treePanel.ScrollViewTo(scrollControl);
}
}
private void OnSearchBoxTextChanged()
{
@@ -211,6 +247,28 @@ namespace FlaxEditor.Windows.Assets
PerformLayout();
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (base.OnMouseUp(location, button))
return true;
if (button == MouseButton.Right && _treePanel.ContainsPoint(ref location))
{
_tree.Deselect();
var locationCM = location + _searchBox.BottomLeft;
ShowContextMenu(Parent, ref locationCM);
return true;
}
if (button == MouseButton.Left && _treePanel.ContainsPoint(ref location))
{
_tree.Deselect();
return true;
}
return false;
}
private void OnScriptsReloadBegin()
{
_isScriptsReloading = true;

View File

@@ -60,23 +60,57 @@ namespace FlaxEditor.Windows
if (isSingleActorSelected)
{
var convertMenu = contextMenu.AddChildMenu("Convert");
var convertActorCm = convertMenu.ContextMenu;
for (int i = 0; i < SpawnActorsGroups.Length; i++)
convertMenu.ContextMenu.AutoSort = true;
foreach (var actorType in Editor.CodeEditing.Actors.Get())
{
var group = SpawnActorsGroups[i];
if (actorType.IsAbstract)
continue;
if (group.Types.Length == 1)
ActorContextMenuAttribute attribute = null;
foreach (var e in actorType.GetAttributes(true))
{
var type = group.Types[0].Value;
convertActorCm.AddButton(group.Types[0].Key, () => Editor.SceneEditing.Convert(type));
}
else
{
var groupCm = convertActorCm.AddChildMenu(group.Name).ContextMenu;
for (int j = 0; j < group.Types.Length; j++)
if (e is ActorContextMenuAttribute actorContextMenuAttribute)
{
var type = group.Types[j].Value;
groupCm.AddButton(group.Types[j].Key, () => Editor.SceneEditing.Convert(type));
attribute = actorContextMenuAttribute;
break;
}
}
if (attribute == null)
continue;
var splitPath = attribute?.Path.Split('/');
ContextMenuChildMenu childCM = convertMenu;
bool mainCM = true;
for (int i = 0; i < splitPath?.Length; i++)
{
if (i == splitPath.Length - 1)
{
if (mainCM)
{
convertMenu.ContextMenu.AddButton(splitPath[i].Trim(), () => Editor.SceneEditing.Convert(actorType.Type));
mainCM = false;
}
else
{
childCM?.ContextMenu.AddButton(splitPath[i].Trim(), () => Editor.SceneEditing.Convert(actorType.Type));
childCM.ContextMenu.AutoSort = true;
}
}
else
{
// Remove new path for converting menu
if (splitPath[i] == "New")
continue;
if (mainCM)
{
childCM = convertMenu.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim());
mainCM = false;
}
else
{
childCM = childCM?.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim());
}
childCM.ContextMenu.AutoSort = true;
}
}
}
@@ -114,24 +148,50 @@ namespace FlaxEditor.Windows
contextMenu.AddSeparator();
var spawnMenu = contextMenu.AddChildMenu("New");
var newActorCm = spawnMenu.ContextMenu;
for (int i = 0; i < SpawnActorsGroups.Length; i++)
// go through each actor and add it to the context menu if it has the ActorContextMenu attribute
foreach (var actorType in Editor.CodeEditing.Actors.Get())
{
var group = SpawnActorsGroups[i];
if (actorType.IsAbstract || !actorType.HasAttribute(typeof(ActorContextMenuAttribute), true))
continue;
if (group.Types.Length == 1)
ActorContextMenuAttribute attribute = null;
foreach (var actorAttribute in actorType.GetAttributes(true))
{
var type = group.Types[0].Value;
newActorCm.AddButton(group.Types[0].Key, () => Spawn(type));
}
else
{
var groupCm = newActorCm.AddChildMenu(group.Name).ContextMenu;
for (int j = 0; j < group.Types.Length; j++)
if (actorAttribute is ActorContextMenuAttribute actorContextMenuAttribute)
{
var type = group.Types[j].Value;
groupCm.AddButton(group.Types[j].Key, () => Spawn(type));
attribute = actorContextMenuAttribute;
}
}
var splitPath = attribute?.Path.Split('/');
ContextMenuChildMenu childCM = null;
bool mainCM = true;
for (int i = 0; i < splitPath?.Length; i++)
{
if (i == splitPath.Length - 1)
{
if (mainCM)
{
contextMenu.AddButton(splitPath[i].Trim(), () => Spawn(actorType.Type));
mainCM = false;
}
else
{
childCM?.ContextMenu.AddButton(splitPath[i].Trim(), () => Spawn(actorType.Type));
childCM.ContextMenu.AutoSort = true;
}
}
else
{
if (mainCM)
{
childCM = contextMenu.GetOrAddChildMenu(splitPath[i].Trim());
mainCM = false;
}
else
{
childCM = childCM?.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim());
}
childCM.ContextMenu.AutoSort = true;
}
}
}

View File

@@ -22,113 +22,6 @@ namespace FlaxEditor.Windows
/// <seealso cref="FlaxEditor.Windows.SceneEditorWindow" />
public partial class SceneTreeWindow : SceneEditorWindow
{
/// <summary>
/// The spawnable actors group.
/// </summary>
public struct ActorsGroup
{
/// <summary>
/// The group name.
/// </summary>
public string Name;
/// <summary>
/// The types to spawn (name and type).
/// </summary>
public KeyValuePair<string, Type>[] Types;
}
/// <summary>
/// The Spawnable actors (groups with single entry are inlined without a child menu)
/// </summary>
public static readonly ActorsGroup[] SpawnActorsGroups =
{
new ActorsGroup
{
Types = new[] { new KeyValuePair<string, Type>("Actor", typeof(EmptyActor)) }
},
new ActorsGroup
{
Types = new[] { new KeyValuePair<string, Type>("Model", typeof(StaticModel)) }
},
new ActorsGroup
{
Types = new[] { new KeyValuePair<string, Type>("Camera", typeof(Camera)) }
},
new ActorsGroup
{
Name = "Lights",
Types = new[]
{
new KeyValuePair<string, Type>("Directional Light", typeof(DirectionalLight)),
new KeyValuePair<string, Type>("Point Light", typeof(PointLight)),
new KeyValuePair<string, Type>("Spot Light", typeof(SpotLight)),
new KeyValuePair<string, Type>("Sky Light", typeof(SkyLight)),
}
},
new ActorsGroup
{
Name = "Visuals",
Types = new[]
{
new KeyValuePair<string, Type>("Environment Probe", typeof(EnvironmentProbe)),
new KeyValuePair<string, Type>("Sky", typeof(Sky)),
new KeyValuePair<string, Type>("Skybox", typeof(Skybox)),
new KeyValuePair<string, Type>("Exponential Height Fog", typeof(ExponentialHeightFog)),
new KeyValuePair<string, Type>("PostFx Volume", typeof(PostFxVolume)),
new KeyValuePair<string, Type>("Decal", typeof(Decal)),
new KeyValuePair<string, Type>("Particle Effect", typeof(ParticleEffect)),
}
},
new ActorsGroup
{
Name = "Physics",
Types = new[]
{
new KeyValuePair<string, Type>("Rigid Body", typeof(RigidBody)),
new KeyValuePair<string, Type>("Character Controller", typeof(CharacterController)),
new KeyValuePair<string, Type>("Box Collider", typeof(BoxCollider)),
new KeyValuePair<string, Type>("Sphere Collider", typeof(SphereCollider)),
new KeyValuePair<string, Type>("Capsule Collider", typeof(CapsuleCollider)),
new KeyValuePair<string, Type>("Mesh Collider", typeof(MeshCollider)),
new KeyValuePair<string, Type>("Fixed Joint", typeof(FixedJoint)),
new KeyValuePair<string, Type>("Distance Joint", typeof(DistanceJoint)),
new KeyValuePair<string, Type>("Slider Joint", typeof(SliderJoint)),
new KeyValuePair<string, Type>("Spherical Joint", typeof(SphericalJoint)),
new KeyValuePair<string, Type>("Hinge Joint", typeof(HingeJoint)),
new KeyValuePair<string, Type>("D6 Joint", typeof(D6Joint)),
}
},
new ActorsGroup
{
Name = "Other",
Types = new[]
{
new KeyValuePair<string, Type>("Animated Model", typeof(AnimatedModel)),
new KeyValuePair<string, Type>("Bone Socket", typeof(BoneSocket)),
new KeyValuePair<string, Type>("CSG Box Brush", typeof(BoxBrush)),
new KeyValuePair<string, Type>("Audio Source", typeof(AudioSource)),
new KeyValuePair<string, Type>("Audio Listener", typeof(AudioListener)),
new KeyValuePair<string, Type>("Scene Animation", typeof(SceneAnimationPlayer)),
new KeyValuePair<string, Type>("Nav Mesh Bounds Volume", typeof(NavMeshBoundsVolume)),
new KeyValuePair<string, Type>("Nav Link", typeof(NavLink)),
new KeyValuePair<string, Type>("Nav Modifier Volume", typeof(NavModifierVolume)),
new KeyValuePair<string, Type>("Spline", typeof(Spline)),
}
},
new ActorsGroup
{
Name = "GUI",
Types = new[]
{
new KeyValuePair<string, Type>("UI Control", typeof(UIControl)),
new KeyValuePair<string, Type>("UI Canvas", typeof(UICanvas)),
new KeyValuePair<string, Type>("Text Render", typeof(TextRender)),
new KeyValuePair<string, Type>("Sprite Render", typeof(SpriteRender)),
}
},
};
private TextBox _searchBox;
private Tree _tree;
private Panel _sceneTreePanel;
@@ -249,7 +142,7 @@ namespace FlaxEditor.Windows
{
if (selection.Count != 0)
Editor.SceneEditing.Select(actor);
actor.TreeNode.StartRenaming();
actor.TreeNode.StartRenaming(this);
}
}
@@ -442,6 +335,15 @@ namespace FlaxEditor.Windows
return true;
}
if (buttons == MouseButton.Left)
{
if (Editor.StateMachine.CurrentState.CanEditScene)
{
Editor.SceneEditing.Deselect();
}
return true;
}
return false;
}