diff --git a/Source/Editor/Modules/PrefabsModule.cs b/Source/Editor/Modules/PrefabsModule.cs
index 3b3054987..2dfb71538 100644
--- a/Source/Editor/Modules/PrefabsModule.cs
+++ b/Source/Editor/Modules/PrefabsModule.cs
@@ -105,6 +105,33 @@ namespace FlaxEditor.Modules
Editor.Windows.ContentWin.NewItem(proxy, actor, contentItem => OnPrefabCreated(contentItem, actor, prefabWindow), actor.Name, rename);
}
+ ///
+ /// Opens a prefab editor window.
+ ///
+ public void OpenPrefab(ActorNode actorNode)
+ {
+ if (actorNode != null)
+ OpenPrefab(actorNode.Actor.PrefabID);
+ }
+
+ ///
+ /// Opens a prefab editor window.
+ ///
+ public void OpenPrefab(Guid prefabID = default)
+ {
+ if (prefabID == Guid.Empty)
+ {
+ var selection = Editor.SceneEditing.Selection.Where(x => x is ActorNode actorNode && actorNode.HasPrefabLink).ToList().BuildNodesParents();
+ if (selection.Count == 0 || !((ActorNode)selection[0]).Actor.HasPrefabLink)
+ return;
+ prefabID = ((ActorNode)selection[0]).Actor.PrefabID;
+ }
+
+ var item = Editor.ContentDatabase.Find(prefabID);
+ if (item != null)
+ Editor.ContentEditing.Open(item);
+ }
+
private void OnPrefabCreated(ContentItem contentItem, Actor actor, Windows.Assets.PrefabWindow prefabWindow)
{
if (contentItem is PrefabItem prefabItem)
diff --git a/Source/Editor/Options/InputBinding.cs b/Source/Editor/Options/InputBinding.cs
index 59954dec5..52341cfc7 100644
--- a/Source/Editor/Options/InputBinding.cs
+++ b/Source/Editor/Options/InputBinding.cs
@@ -8,6 +8,7 @@ using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Elements;
using FlaxEngine;
using FlaxEngine.GUI;
+using static FlaxEditor.Viewport.EditorViewport;
namespace FlaxEditor.Options
{
@@ -18,7 +19,7 @@ namespace FlaxEditor.Options
[HideInEditor]
[TypeConverter(typeof(InputBindingConverter))]
[CustomEditor(typeof(InputBindingEditor))]
- public struct InputBinding
+ public struct InputBinding : IEquatable
{
///
/// The key to bind.
@@ -251,6 +252,40 @@ namespace FlaxEditor.Options
}
return result;
}
+
+ ///
+ public bool Equals(InputBinding other)
+ {
+ return Key == other.Key && Modifier1 == other.Modifier1 && Modifier2 == other.Modifier2;
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is InputBinding other && Equals(other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((int)Key, (int)Modifier1, (int)Modifier2);
+ }
+
+ ///
+ /// Compares two values.
+ ///
+ public static bool operator ==(InputBinding left, InputBinding right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Compares two values.
+ ///
+ public static bool operator !=(InputBinding left, InputBinding right)
+ {
+ return !left.Equals(right);
+ }
}
class InputBindingConverter : TypeConverter
@@ -522,5 +557,27 @@ namespace FlaxEditor.Options
return false;
}
+
+ ///
+ /// Invokes a specific binding.
+ ///
+ /// The editor instance.
+ /// The binding to execute.
+ /// True if event has been handled, otherwise false.
+ public bool Invoke(Editor editor, InputBinding binding)
+ {
+ if (binding == new InputBinding())
+ return false;
+ var options = editor.Options.Options.Input;
+ for (int i = 0; i < Bindings.Count; i++)
+ {
+ if (Bindings[i].Binder(options) == binding)
+ {
+ Bindings[i].Callback();
+ return true;
+ }
+ }
+ return false;
+ }
}
}
diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs
index 76610f675..721b8d6b1 100644
--- a/Source/Editor/Options/InputOptions.cs
+++ b/Source/Editor/Options/InputOptions.cs
@@ -7,6 +7,32 @@ using FlaxEngine;
namespace FlaxEditor.Options
{
+ ///
+ /// Action to perform when a Scene Node receive a double mouse left click.
+ ///
+ public enum SceneNodeDoubleClick
+ {
+ ///
+ /// Toggles expand/state of the node.
+ ///
+ Expand,
+
+ ///
+ /// Rename the node.
+ ///
+ RenameActor,
+
+ ///
+ /// Focus the object in the viewport.
+ ///
+ FocusActor,
+
+ ///
+ /// If possible, open the scene node in an associated Editor (eg. Prefab Editor).
+ ///
+ OpenPrefab,
+ }
+
///
/// Input editor options data container.
///
@@ -344,6 +370,10 @@ namespace FlaxEditor.Options
[EditorDisplay("Interface"), EditorOrder(2020)]
public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift);
+ [DefaultValue(SceneNodeDoubleClick.None)]
+ [EditorDisplay("Interface"), EditorOrder(2030)]
+ public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.None;
+
#endregion
}
}
diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
index b6b69950d..a1b709efd 100644
--- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
+++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
@@ -8,6 +8,7 @@ using FlaxEditor.Content;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
+using FlaxEditor.Options;
using FlaxEditor.Scripting;
using FlaxEditor.Utilities;
using FlaxEditor.Windows;
@@ -15,7 +16,6 @@ using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
-using Object = FlaxEngine.Object;
namespace FlaxEditor.SceneGraph.GUI
{
@@ -393,7 +393,7 @@ namespace FlaxEditor.SceneGraph.GUI
///
/// Starts the actor renaming action.
///
- public void StartRenaming(EditorWindow window, Panel treePanel = null)
+ public void StartRenaming(EditorWindow window = null, Panel treePanel = null)
{
// Block renaming during scripts reload
if (Editor.Instance.ProgressReporting.CompileScripts.IsActive)
@@ -461,6 +461,30 @@ namespace FlaxEditor.SceneGraph.GUI
}
}
+ ///
+ protected override bool OnMouseDoubleClickHeader(ref Float2 location, MouseButton button)
+ {
+ if (button == MouseButton.Left)
+ {
+ var sceneContext = this.GetSceneContext();
+ switch (Editor.Instance.Options.Options.Input.DoubleClickSceneNode)
+ {
+ case SceneNodeDoubleClick.RenameActor:
+ sceneContext.RenameSelection();
+ return true;
+ case SceneNodeDoubleClick.FocusActor:
+ sceneContext.FocusSelection();
+ return true;
+ case SceneNodeDoubleClick.OpenPrefab:
+ Editor.Instance.Prefabs.OpenPrefab(ActorNode);
+ return true;
+ case SceneNodeDoubleClick.Expand:
+ default: break;
+ }
+ }
+ return base.OnMouseDoubleClickHeader(ref location, button);
+ }
+
///
protected override DragDropEffect OnDragEnterHeader(DragData data)
{
diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs
index 6197d9eb2..c9600b089 100644
--- a/Source/Editor/Utilities/Utils.cs
+++ b/Source/Editor/Utilities/Utils.cs
@@ -1544,5 +1544,12 @@ namespace FlaxEditor.Utilities
}
return path;
}
+
+ internal static ISceneContextWindow GetSceneContext(this Control c)
+ {
+ while (c != null && !(c is ISceneContextWindow))
+ c = c.Parent;
+ return c as ISceneContextWindow;
+ }
}
}
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
index 6a786cb3a..081573b40 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Drag;
@@ -86,7 +85,7 @@ namespace FlaxEditor.Windows.Assets
{
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
}
-
+
private static bool ValidateDragControlType(ScriptType controlType)
{
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
@@ -171,7 +170,8 @@ namespace FlaxEditor.Windows.Assets
var actor = item.OnEditorDrop(this);
actor.Name = item.ShortName;
_window.Spawn(actor);
- var graphNode = _window.Graph.Root.Find(actor);;
+ var graphNode = _window.Graph.Root.Find(actor);
+ ;
if (graphNode != null)
graphNodes.Add(graphNode);
}
@@ -235,7 +235,8 @@ namespace FlaxEditor.Windows.Assets
}
actor.Name = actorType.Name;
_window.Spawn(actor);
- var graphNode = _window.Graph.Root.Find(actor);;
+ var graphNode = _window.Graph.Root.Find(actor);
+ ;
if (graphNode != null)
graphNodes.Add(graphNode);
}
@@ -290,7 +291,7 @@ namespace FlaxEditor.Windows.Assets
// Basic editing options
- var b = contextMenu.AddButton("Rename", Rename);
+ var b = contextMenu.AddButton("Rename", RenameSelection);
b.Enabled = isSingleActorSelected;
b = contextMenu.AddButton("Duplicate", Duplicate);
@@ -414,7 +415,8 @@ namespace FlaxEditor.Windows.Assets
contextMenu.Show(parent, location);
}
- private void Rename()
+ ///
+ public void RenameSelection()
{
var selection = Selection;
if (selection.Count != 0 && selection[0] is ActorNode actor)
@@ -425,6 +427,12 @@ namespace FlaxEditor.Windows.Assets
}
}
+ ///
+ public void FocusSelection()
+ {
+ _viewport.FocusSelection();
+ }
+
///
/// Spawns the specified actor to the prefab (adds actor to root).
///
@@ -468,7 +476,7 @@ namespace FlaxEditor.Windows.Assets
// Spawn it
Spawn(actor);
- Rename();
+ RenameSelection();
}
///
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs
index 5bf3236ee..533735c93 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.cs
@@ -19,7 +19,7 @@ namespace FlaxEditor.Windows.Assets
///
///
///
- public sealed partial class PrefabWindow : AssetEditorWindowBase, IPresenterOwner
+ public sealed partial class PrefabWindow : AssetEditorWindowBase, IPresenterOwner, ISceneContextWindow
{
private readonly SplitPanel _split1;
private readonly SplitPanel _split2;
@@ -212,8 +212,8 @@ namespace FlaxEditor.Windows.Assets
InputActions.Add(options => options.Paste, Paste);
InputActions.Add(options => options.Duplicate, Duplicate);
InputActions.Add(options => options.Delete, Delete);
- InputActions.Add(options => options.Rename, Rename);
- InputActions.Add(options => options.FocusSelection, _viewport.FocusSelection);
+ InputActions.Add(options => options.Rename, RenameSelection);
+ InputActions.Add(options => options.FocusSelection, FocusSelection);
}
///
diff --git a/Source/Editor/Windows/SceneEditorWindow.cs b/Source/Editor/Windows/SceneEditorWindow.cs
index bcdc96480..62922ebed 100644
--- a/Source/Editor/Windows/SceneEditorWindow.cs
+++ b/Source/Editor/Windows/SceneEditorWindow.cs
@@ -1,14 +1,32 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
+using FlaxEditor.SceneGraph;
+using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows
{
+ ///
+ /// Shared interface for scene editing utilities.
+ ///
+ public interface ISceneContextWindow
+ {
+ ///
+ /// Opends popup for renaming selected objects.
+ ///
+ void RenameSelection();
+
+ ///
+ /// Focuses selected objects.
+ ///
+ void FocusSelection();
+ }
+
///
/// Base class for editor windows dedicated to scene editing.
///
///
- public abstract class SceneEditorWindow : EditorWindow
+ public abstract class SceneEditorWindow : EditorWindow, ISceneContextWindow
{
///
/// Initializes a new instance of the class.
@@ -21,5 +39,38 @@ namespace FlaxEditor.Windows
{
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
}
+
+ ///
+ public void FocusSelection()
+ {
+ Editor.Windows.EditWin.Viewport.FocusSelection();
+ }
+
+ ///
+ public void RenameSelection()
+ {
+ var selection = Editor.SceneEditing.Selection;
+ var selectionCount = selection.Count;
+
+ // Show a window with options to rename multiple actors.
+ if (selectionCount > 1)
+ {
+ var selectedActors = new Actor[selectionCount];
+
+ for (int i = 0; i < selectionCount; i++)
+ if (selection[i] is ActorNode actorNode)
+ selectedActors[i] = actorNode.Actor;
+
+ RenameWindow.Show(selectedActors, Editor);
+ return;
+ }
+
+ if (selectionCount != 0 && selection[0] is ActorNode actor)
+ {
+ Editor.SceneEditing.Select(actor);
+ var sceneWindow = Editor.Windows.SceneWin;
+ actor.TreeNode.StartRenaming(sceneWindow, sceneWindow.SceneTreePanel);
+ }
+ }
}
}
diff --git a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
index a107a72f5..8591ecb9f 100644
--- a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
@@ -53,7 +53,7 @@ namespace FlaxEditor.Windows
// Basic editing options
var firstSelection = hasSthSelected ? Editor.SceneEditing.Selection[0] as ActorNode : null;
- b = contextMenu.AddButton("Rename", inputOptions.Rename, Rename);
+ b = contextMenu.AddButton("Rename", inputOptions.Rename, RenameSelection);
b.Enabled = hasSthSelected;
b = contextMenu.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
b.Enabled = hasSthSelected && (firstSelection != null ? firstSelection.CanDuplicate : true);
@@ -145,6 +145,7 @@ namespace FlaxEditor.Windows
bool hasPrefabLink = canEditScene && isSingleActorSelected && (firstSelection != null ? firstSelection.HasPrefabLink : false);
if (hasPrefabLink)
{
+ contextMenu.AddButton("Open Prefab", () => Editor.Prefabs.OpenPrefab(firstSelection));
contextMenu.AddButton("Select Prefab", Editor.Prefabs.SelectPrefab);
contextMenu.AddButton("Break Prefab Link", Editor.Prefabs.BreakLinks);
}
diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs
index 42dc0ffbe..7b5e84c02 100644
--- a/Source/Editor/Windows/SceneTreeWindow.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.cs
@@ -96,7 +96,7 @@ namespace FlaxEditor.Windows
InputActions.Add(options => options.ScaleMode, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
InputActions.Add(options => options.FocusSelection, () => Editor.Windows.EditWin.Viewport.FocusSelection());
InputActions.Add(options => options.LockFocusSelection, () => Editor.Windows.EditWin.Viewport.LockFocusSelection());
- InputActions.Add(options => options.Rename, Rename);
+ InputActions.Add(options => options.Rename, RenameSelection);
}
///
@@ -143,31 +143,6 @@ namespace FlaxEditor.Windows
PerformLayout();
}
- private void Rename()
- {
- var selection = Editor.SceneEditing.Selection;
- var selectionCount = selection.Count;
-
- // Show a window with options to rename multiple actors.
- if (selectionCount > 1)
- {
- var selectedActors = new Actor[selectionCount];
-
- for (int i = 0; i < selectionCount; i++)
- if (selection[i] is ActorNode actorNode)
- selectedActors[i] = actorNode.Actor;
-
- RenameWindow.Show(selectedActors, Editor);
- return;
- }
-
- if (selectionCount != 0 && selection[0] is ActorNode actor)
- {
- Editor.SceneEditing.Select(actor);
- actor.TreeNode.StartRenaming(this, _sceneTreePanel);
- }
- }
-
private void Spawn(Type type)
{
// Create actor
@@ -197,7 +172,7 @@ namespace FlaxEditor.Windows
Editor.SceneEditing.Spawn(actor, parentActor);
Editor.SceneEditing.Select(actor);
- Rename();
+ RenameSelection();
}
///
@@ -293,7 +268,7 @@ namespace FlaxEditor.Windows
{
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
}
-
+
private static bool ValidateDragControlType(ScriptType controlType)
{
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);