diff --git a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
index f4a49195f..8d31b2744 100644
--- a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
@@ -54,8 +54,6 @@ namespace FlaxEditor.Windows
// Basic editing options
b = contextMenu.AddButton("Rename", inputOptions.Rename, Rename);
- b.Enabled = isSingleActorSelected;
-
b = contextMenu.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
b.Enabled = hasSthSelected;
diff --git a/Source/Editor/Windows/SceneTreeWindow.RenameWindow.cs b/Source/Editor/Windows/SceneTreeWindow.RenameWindow.cs
new file mode 100644
index 000000000..6278a5f3b
--- /dev/null
+++ b/Source/Editor/Windows/SceneTreeWindow.RenameWindow.cs
@@ -0,0 +1,246 @@
+using System.Text;
+using FlaxEngine;
+using FlaxEngine.GUI;
+using FlaxEditor.GUI;
+
+namespace FlaxEditor.Windows
+{
+ ///
+ /// A window used to rename multiple actors.
+ ///
+ public class RenameWindow : EditorWindow
+ {
+ ///
+ private class RenameUndoAction : IUndoAction
+ {
+ ///
+ /// The old actors name to use on action.
+ ///
+ public string[] OldNames;
+
+ ///
+ /// The new actors name to use on action.
+ ///
+ public string[] NewNames;
+
+ ///
+ /// All actors to rename.
+ ///
+ public Actor[] ActorsToRename;
+
+ ///
+ /// Create a undo action.
+ ///
+ ///
+ public RenameUndoAction(Actor[] nodes)
+ {
+ ActorsToRename = nodes;
+ OldNames = new string[nodes.Length];
+
+ for (int i = 0; i < nodes.Length; i++)
+ OldNames[i] = nodes[i].Name;
+ }
+
+ ///
+ public void Do()
+ {
+ for (int i = 0; i < ActorsToRename.Length; i++)
+ ActorsToRename[i].Name = NewNames[i];
+ }
+
+ ///
+ public void Undo()
+ {
+ for (int i = 0; i < ActorsToRename.Length; i++)
+ ActorsToRename[i].Name = OldNames[i];
+ }
+
+ ///
+ public string ActionString => "Renaming actors.";
+
+ ///
+ public void Dispose() { }
+ }
+
+ ///
+ /// Rename options.
+ ///
+ private enum RenameOptions
+ {
+ OnlyName,
+ UsePrefix,
+ UseSuffix
+ }
+
+ private string _newActorsName;
+ private RenameOptions _renameOption;
+ private Actor[] _actorsToRename;
+
+ private static RenameWindow _currentOpenedWindow;
+
+ private RenameWindow(Actor[] actorsToRename, Editor editor) : base(editor, true, FlaxEngine.GUI.ScrollBars.None)
+ {
+ Title = "Rename";
+ Size = new Float2(300, 110);
+
+ _newActorsName = "Actor ";
+ _renameOption = RenameOptions.UseSuffix;
+ _actorsToRename = actorsToRename;
+
+ var container = new VerticalPanel
+ {
+ Parent = this,
+ AnchorPreset = AnchorPresets.StretchAll,
+ Offset = Vector2.Zero,
+ AutoSize = false,
+ Bounds = Rectangle.Empty
+ };
+
+ var nameContainer = new HorizontalPanel
+ {
+ Parent = container,
+ AnchorPreset = AnchorPresets.TopLeft,
+ Bounds = new Rectangle(0, 0, 300, 22),
+ Offset = Vector2.Zero,
+ AutoSize = false,
+ Spacing = 2,
+ CullChildren = false,
+ ClipChildren = false,
+ };
+
+ var optionsContainer = new HorizontalPanel
+ {
+ Parent = container,
+ AnchorPreset = AnchorPresets.TopLeft,
+ Bounds = new Rectangle(0, 22, 300, 22),
+ Offset = Vector2.Zero,
+ AutoSize = false,
+ Spacing = 2,
+ CullChildren = false,
+ ClipChildren = false,
+ };
+
+ var renameLabel = new Label
+ {
+ Text = "New Name",
+ AnchorPreset = AnchorPresets.Custom,
+ AnchorMin = Float2.Zero,
+ AnchorMax = new Float2(0.5f, 0),
+ Parent = nameContainer,
+ HorizontalAlignment = TextAlignment.Near,
+ Size = new Float2(150, 22),
+ Offsets = Margin.Zero,
+ };
+
+ var newNameTextBox = new TextBox
+ {
+ Text = _newActorsName,
+ AnchorPreset = AnchorPresets.Custom,
+ AnchorMin = new Float2(0.5f, 0),
+ AnchorMax = new Float2(1, 0),
+ Parent = nameContainer,
+ Size = new Float2(150, 22),
+ Offsets = Margin.Zero,
+ };
+
+ var optionNameLabel = new Label
+ {
+ Text = "Rename Option",
+ HorizontalAlignment = TextAlignment.Near,
+ AnchorPreset = AnchorPresets.Custom,
+ AnchorMin = Float2.Zero,
+ AnchorMax = new Float2(0.5f, 0),
+ Parent = optionsContainer,
+ Size = new Float2(150, 22),
+ Offsets = Margin.Zero,
+ };
+
+ var renameOptions = new EnumComboBox(typeof(RenameOptions))
+ {
+ Parent = optionsContainer,
+ Value = (int)_renameOption,
+ AnchorPreset = AnchorPresets.Custom,
+ AnchorMin = new Float2(0.5f, 0f),
+ AnchorMax = new Float2(1, 0),
+ Size = new Float2(150, 22),
+ Offsets = Margin.Zero,
+ };
+
+ var renameButton = new Button
+ {
+ Text = "Rename",
+ AnchorPreset = AnchorPresets.TopLeft,
+ Parent = container,
+ };
+
+ newNameTextBox.TextBoxEditEnd += textBox =>
+ {
+ _newActorsName = textBox.Text;
+ };
+
+ renameOptions.EnumValueChanged += combo =>
+ {
+ _renameOption = (RenameOptions)combo.Value;
+ };
+
+ newNameTextBox.Focus();
+ newNameTextBox.KeyDown += k =>
+ {
+ if (k == KeyboardKeys.Return)
+ {
+ _newActorsName = newNameTextBox.Text;
+ RenameActors();
+ }
+ };
+
+ renameButton.Clicked += RenameActors;
+ }
+
+ private void RenameActors()
+ {
+ var renameUndoAction = new RenameUndoAction(_actorsToRename);
+ Editor.Instance.SceneEditing.Undo.AddAction(renameUndoAction);
+ renameUndoAction.NewNames = new string[_actorsToRename.Length];
+ for (int i = 0; i < _actorsToRename.Length; i++)
+ {
+ var actor = _actorsToRename[i];
+ if (!actor)
+ continue;
+ var newName = new StringBuilder(_newActorsName);
+ if (_renameOption == RenameOptions.UsePrefix)
+ {
+ newName = new StringBuilder();
+ newName.Append(i);
+ newName.Append(_newActorsName);
+ }
+ else if (_renameOption == RenameOptions.UseSuffix)
+ newName.Append(i.ToString());
+
+ var newNameStr = newName.ToString();
+ actor.Name = newNameStr;
+ renameUndoAction.NewNames[i] = newNameStr;
+ }
+ Editor.Instance.Scene.MarkAllScenesEdited();
+ Close();
+ }
+
+ ///
+ /// Create an instance of the to rename actors and show the window.
+ ///
+ /// All actors to rename
+ /// The editor.
+ public static void Show(Actor[] actorsToRename, Editor editor)
+ {
+ // Can only one window opened.
+ if (_currentOpenedWindow != null)
+ _currentOpenedWindow.Close(ClosingReason.CloseEvent);
+
+ _currentOpenedWindow = new RenameWindow(actorsToRename, editor);
+ _currentOpenedWindow.ShowFloating(new Float2(300, 110));
+ _currentOpenedWindow.RootWindow.Window.Closed += () =>
+ {
+ _currentOpenedWindow = null;
+ };
+ }
+ }
+}
diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs
index 8408f574e..42dc0ffbe 100644
--- a/Source/Editor/Windows/SceneTreeWindow.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.cs
@@ -146,10 +146,24 @@ namespace FlaxEditor.Windows
private void Rename()
{
var selection = Editor.SceneEditing.Selection;
- if (selection.Count != 0 && selection[0] is ActorNode actor)
+ var selectionCount = selection.Count;
+
+ // Show a window with options to rename multiple actors.
+ if (selectionCount > 1)
{
- if (selection.Count != 0)
- Editor.SceneEditing.Select(actor);
+ 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);
}
}