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); } }