Merge branch 'add-tree-view-shortcuts' of https://github.com/Tryibion/FlaxEngine into Tryibion-add-tree-view-shortcuts

This commit is contained in:
2026-04-18 23:44:58 +02:00
4 changed files with 245 additions and 37 deletions
@@ -128,28 +128,6 @@ public sealed class ContentItemTreeNode : TreeNode, IContentItemOwner
return base.OnMouseDoubleClickHeader(ref location, button);
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.Return:
Editor.Instance.Windows.ContentWin.Open(Item);
return true;
case KeyboardKeys.F2:
Editor.Instance.Windows.ContentWin.Rename(Item);
return true;
case KeyboardKeys.Delete:
Editor.Instance.Windows.ContentWin.Delete(Item);
return true;
}
}
return base.OnKeyDown(key);
}
/// <inheritdoc />
protected override void DoDragDrop()
{
+207
View File
@@ -0,0 +1,207 @@
using System.Collections.Generic;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Options;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content;
/// <summary>
/// The content tree view panel.
/// </summary>
public class TreeViewPanel : Panel
{
/// <summary>
/// The content tree assigned to this panel.
/// </summary>
public Tree ContentTree;
private InputActionsContainer _inputActions;
private bool _isCutting;
private List<ContentItem> _cutItems = new List<ContentItem>();
/// <summary>
/// Initializes a new instance of the <see cref="TreeViewPanel"/> class.
/// </summary>
public TreeViewPanel()
: base(ScrollBars.None)
{
// Setup input actions
_inputActions = new InputActionsContainer(new[]
{
new InputActionsContainer.Binding(options => options.Rename, Rename),
new InputActionsContainer.Binding(options => options.Delete, Delete),
new InputActionsContainer.Binding(options => options.Duplicate, Duplicate),
new InputActionsContainer.Binding(options => options.Copy, Copy),
new InputActionsContainer.Binding(options => options.Paste, Paste),
new InputActionsContainer.Binding(options => options.Cut, Cut),
});
}
/// <summary>
/// Renames the selected item.
/// </summary>
public void Rename()
{
if (ContentTree == null || !Visible)
return;
var selection = ContentTree.Selection;
if (selection.Count > 0)
{
var node = selection[0];
if (node is ContentItemTreeNode contentNode)
{
Editor.Instance.Windows.ContentWin.Rename(contentNode.Item);
}
}
}
/// <summary>
/// Deletes the selected items.
/// </summary>
public void Delete()
{
if (ContentTree == null || !Visible)
return;
var selection = ContentTree.Selection;
if (selection.Count > 0)
{
var items = new List<ContentItem>();
foreach (var node in selection)
{
if (node is ContentItemTreeNode contentNode)
{
items.Add(contentNode.Item);
}
}
Editor.Instance.Windows.ContentWin.Delete(items);
}
}
/// <summary>
/// Duplicates the selected items.
/// </summary>
public void Duplicate()
{
if (ContentTree == null || !Visible)
return;
var selection = ContentTree.Selection;
if (selection.Count > 0)
{
var items = new List<ContentItem>();
foreach (var node in selection)
{
if (node is ContentItemTreeNode contentNode)
{
items.Add(contentNode.Item);
}
}
Editor.Instance.Windows.ContentWin.Duplicate(items);
}
}
/// <summary>
/// Copies the items.
/// </summary>
public void Copy()
{
if (ContentTree == null || !Visible)
return;
var selection = ContentTree.Selection;
if (selection.Count == 0)
return;
var filePaths = new List<string>();
foreach (var node in selection)
if (node is ContentItemTreeNode contentNode)
filePaths.Add(contentNode.Item.Path);
Clipboard.Files = filePaths.ToArray();
UpdateContentItemCut(false);
}
/// <summary>
/// Pastes the items.
/// </summary>
public void Paste()
{
if (ContentTree == null || !Visible)
return;
var files = Clipboard.Files;
if (files == null || files.Length == 0)
return;
Editor.Instance.Windows.ContentWin.Paste(files, _isCutting);
UpdateContentItemCut(false);
}
/// <summary>
/// Cuts the items.
/// </summary>
public void Cut()
{
if (ContentTree == null || !Visible)
return;
Copy();
UpdateContentItemCut(true);
}
private void UpdateContentItemCut(bool cut)
{
_isCutting = cut;
// Add selection to cut list
if (cut)
{
var selection = ContentTree.Selection;
foreach (var node in selection)
{
if (node is ContentItemTreeNode contentNode)
_cutItems.Add(contentNode.Item);
}
}
// Update item with if it is being cut.
foreach (var item in _cutItems)
{
item.IsBeingCut = cut;
}
// Clean up cut items
if (!cut)
_cutItems.Clear();
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (!Visible)
return false;
if (ContentTree == null)
return base.OnKeyDown(key);
if (_inputActions.Process(Editor.Instance, this, key))
return true;
var selection = ContentTree.Selection;
if (selection.Count > 0)
{
if (key == KeyboardKeys.Return)
{
foreach (var node in selection)
{
if (node is ContentItemTreeNode contentNode)
Editor.Instance.Windows.ContentWin.Open(contentNode.Item);
}
}
}
return base.OnKeyDown(key);
}
}
@@ -67,12 +67,28 @@ namespace FlaxEditor.Windows
b = cm.AddButton("Open", () => Open(item));
b.Enabled = proxy != null || isFolder;
if (_view.SelectedCount > 1)
b = cm.AddButton("Open (all selected)", () =>
if (_showAllContentInTree)
{
var selection = _tree.Selection;
if (selection.Count > 0)
{
foreach (var e in _view.Selection)
Open(e);
});
b = cm.AddButton("Open (all selected)", () =>
{
foreach (var e in _tree.Selection)
if (e is ContentItemTreeNode contentNode)
Open(contentNode.Item);
});
}
}
else
{
if (_view.SelectedCount > 1)
b = cm.AddButton("Open (all selected)", () =>
{
foreach (var e in _view.Selection)
Open(e);
});
}
cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(item.Path)));
@@ -137,12 +153,21 @@ namespace FlaxEditor.Windows
{
cm.AddButton("Delete", () => Delete(item));
cm.AddSeparator();
cm.AddButton("Duplicate", _view.Duplicate);
cm.AddButton("Cut", _view.Cut);
cm.AddButton("Copy", _view.Copy);
if (_showAllContentInTree)
{
cm.AddButton("Duplicate", _treeOnlyPanel.Duplicate);
cm.AddButton("Cut", _treeOnlyPanel.Cut);
cm.AddButton("Copy", _treeOnlyPanel.Copy);
}
else
{
cm.AddButton("Duplicate", _view.Duplicate);
cm.AddButton("Cut", _view.Cut);
cm.AddButton("Copy", _view.Copy);
}
}
b = cm.AddButton("Paste", _view.Paste);
b = _showAllContentInTree ? cm.AddButton("Paste", _treeOnlyPanel.Paste) : cm.AddButton("Paste", _view.Paste);
b.Enabled = _view.CanPaste();
if (isFolder && folder.Node is MainContentFolderTreeNode)
+4 -6
View File
@@ -32,7 +32,7 @@ namespace FlaxEditor.Windows
private string _workspaceRebuildLocation;
private string _lastViewedFolderBeforeReload;
private SplitPanel _split;
private Panel _treeOnlyPanel;
private TreeViewPanel _treeOnlyPanel;
private ContainerControl _treePanelRoot;
private ContainerControl _treeHeaderPanel;
private Panel _contentItemsSearchPanel;
@@ -186,7 +186,7 @@ namespace FlaxEditor.Windows
};
// Tree-only panel (used when showing all content in the tree)
_treeOnlyPanel = new Panel(ScrollBars.None)
_treeOnlyPanel = new TreeViewPanel
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0, 0, _toolStrip.Bottom, 0),
@@ -237,6 +237,7 @@ namespace FlaxEditor.Windows
Parent = _contentTreePanel,
};
_tree.SelectedChanged += OnTreeSelectionChanged;
_treeOnlyPanel.ContentTree = _tree;
// Content items searching query input box and filters selector
_contentItemsSearchPanel = new Panel
@@ -632,11 +633,7 @@ namespace FlaxEditor.Windows
var area = node.TextRect;
const float minRenameWidth = 220.0f;
if (area.Width < minRenameWidth)
{
float expand = minRenameWidth - area.Width;
area.X -= expand * 0.5f;
area.Width = minRenameWidth;
}
area.Y -= 2;
area.Height += 4.0f;
popup = RenamePopup.Show(node, area, item.ShortName, true);
@@ -889,6 +886,7 @@ namespace FlaxEditor.Windows
// Refresh this folder now and try to find duplicated item
Editor.ContentDatabase.RefreshFolder(item.ParentFolder, true);
RefreshView();
RefreshTreeItems();
var targetItem = item.ParentFolder.FindChild(targetPath);
// Start renaming it