Merge branch 'NoriteSC-ContentBrowserImprovement'

This commit is contained in:
Wojtek Figat
2023-09-11 20:03:51 +02:00
11 changed files with 284 additions and 85 deletions

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Drag;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -31,7 +32,7 @@ namespace FlaxEditor.Content.GUI
: base(x, y, height)
{
TargetNode = targetNode;
Text = targetNode.NavButtonLabel + "/";
Text = targetNode.NavButtonLabel;
}
/// <inheritdoc />
@@ -72,7 +73,6 @@ namespace FlaxEditor.Content.GUI
if (_dragOverItems == null)
_dragOverItems = new DragItems(ValidateDragItem);
_dragOverItems.OnDragEnter(data);
var result = GetDragEffect(data);
_validDragOver = result != DragDropEffect.None;
@@ -122,4 +122,70 @@ namespace FlaxEditor.Content.GUI
return result;
}
}
sealed class ContentNavigationSeparator : ComboBox
{
public ContentNavigationButton Target;
public ContentNavigationSeparator(ContentNavigationButton target, float x, float y, float height)
{
Target = target;
Bounds = new Rectangle(x, y, 16, height);
Offsets = new Margin(Bounds.X, Bounds.Width, Bounds.Y, Bounds.Height);
UpdateTransform();
MaximumItemsInViewCount = 20;
var style = Style.Current;
BackgroundColor = style.BackgroundNormal;
BackgroundColorHighlighted = BackgroundColor;
BackgroundColorSelected = BackgroundColor;
}
protected override ContextMenu OnCreatePopup()
{
// Update items
ClearItems();
foreach (var child in Target.TargetNode.Children)
{
if (child is ContentTreeNode node)
{
if (node.Folder.VisibleInHierarchy) // Respect the filter set by ContentFilterConfig.Filter(...)
AddItem(node.Folder.ShortName);
}
}
return base.OnCreatePopup();
}
public override void Draw()
{
var style = Style.Current;
var rect = new Rectangle(Float2.Zero, Size);
var color = IsDragOver ? style.BackgroundSelected * 0.6f : (_mouseDown ? style.BackgroundSelected : (IsMouseOver ? style.BackgroundHighlighted : Color.Transparent));
Render2D.FillRectangle(rect, color);
Render2D.DrawSprite(Editor.Instance.Icons.ArrowRight12, new Rectangle(rect.Location.X, rect.Y + rect.Size.Y * 0.25f, rect.Size.X, rect.Size.X), EnabledInHierarchy ? style.Foreground : style.ForegroundDisabled);
}
protected override void OnLayoutMenuButton(ContextMenuButton button, int index, bool construct = false)
{
button.Icon = Editor.Instance.Icons.FolderClosed32;
if (_tooltips != null && _tooltips.Length > index)
button.TooltipText = _tooltips[index];
}
protected override void OnItemClicked(int index)
{
base.OnItemClicked(index);
var item = _items[index];
foreach (var child in Target.TargetNode.Children)
{
if (child is ContentTreeNode node && node.Folder.ShortName == item)
{
Editor.Instance.Windows.ContentWin.Navigate(node);
return;
}
}
}
}
}

View File

@@ -261,11 +261,14 @@ namespace FlaxEditor.Content.GUI
ClearItems();
// Add references and link items
_items.AddRange(items);
for (int i = 0; i < items.Count; i++)
{
items[i].Parent = this;
items[i].AddReference(this);
if (items[i].Visible)
{
items[i].Parent = this;
items[i].AddReference(this);
_items.Add(items[i]);
}
}
if (selection != null)
{

View File

@@ -441,6 +441,9 @@ namespace FlaxEditor.Content
{
get
{
// Skip when hidden
if (!Visible)
return Rectangle.Empty;
var view = Parent as ContentView;
var size = Size;
switch (view?.ViewType ?? ContentViewType.Tiles)
@@ -666,7 +669,6 @@ namespace FlaxEditor.Content
/// <inheritdoc />
public override void Draw()
{
// Cache data
var size = Size;
var style = Style.Current;
var view = Parent as ContentView;

View File

@@ -17,6 +17,6 @@ namespace FlaxEditor.Content
}
/// <inheritdoc />
public override string NavButtonLabel => string.Empty;
public override string NavButtonLabel => " /";
}
}

View File

@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -396,14 +397,24 @@ namespace FlaxEditor.GUI
_popupMenu.ButtonClicked += btn =>
{
OnItemClicked((int)btn.Tag);
_popupMenu?.Hide();
if (SupportMultiSelect)
{
// Don't hide in multi-select, so user can edit multiple elements instead of just one
UpdateButtons();
_popupMenu?.PerformLayout();
}
else
{
_popupMenu?.Hide();
}
};
}
// Check if menu hs been already shown
if (_popupMenu.Visible)
{
_popupMenu.Hide();
if (!SupportMultiSelect)
_popupMenu.Hide();
return;
}
@@ -412,27 +423,7 @@ namespace FlaxEditor.GUI
// Check if has any items
if (_items.Count > 0)
{
// Setup items list
var itemControls = _popupMenu.Items.ToArray();
foreach (var e in itemControls)
e.Dispose();
if (Sorted)
_items.Sort();
var style = Style.Current;
for (int i = 0; i < _items.Count; i++)
{
var btn = _popupMenu.AddButton(_items[i]);
if (_selectedIndices.Contains(i))
{
btn.Icon = style.CheckBoxTick;
}
if (_tooltips != null && _tooltips.Length > i)
{
btn.TooltipText = _tooltips[i];
}
btn.Tag = i;
}
UpdateButtons();
// Show dropdown list
_popupMenu.MinimumWidth = Width;
@@ -440,6 +431,54 @@ namespace FlaxEditor.GUI
}
}
/// <summary>
/// Updates buttons layout.
/// </summary>
private void UpdateButtons()
{
if (_popupMenu.Items.Count() != _items.Count)
{
var itemControls = _popupMenu.Items.ToArray();
foreach (var e in itemControls)
e.Dispose();
if (Sorted)
_items.Sort();
for (int i = 0; i < _items.Count; i++)
{
var btn = _popupMenu.AddButton(_items[i]);
OnLayoutMenuButton(btn, i, true);
btn.Tag = i;
}
}
else
{
var itemControls = _popupMenu.Items.ToArray();
if (Sorted)
_items.Sort();
for (int i = 0; i < _items.Count; i++)
{
if (itemControls[i] is ContextMenuButton btn)
{
btn.Text = _items[i];
OnLayoutMenuButton(btn, i, true);
}
}
}
}
/// <summary>
/// Called when button is created or updated. Can be used to customize the visuals.
/// </summary>
/// <param name="button">The button.</param>
/// <param name="index">The item index.</param>
/// <param name="construct">true if button is created else it is repainting the button</param>
protected virtual void OnLayoutMenuButton(ContextMenuButton button, int index, bool construct = false)
{
button.Checked = _selectedIndices.Contains(index);
if (_tooltips != null && _tooltips.Length > index)
button.TooltipText = _tooltips[index];
}
/// <summary>
/// Creates the popup menu.
/// </summary>
@@ -460,6 +499,8 @@ namespace FlaxEditor.GUI
_popupMenu = null;
}
if (IsDisposing)
return;
_selectedIndices.Clear();
_selectedIndices = null;
_items.Clear();

View File

@@ -138,7 +138,7 @@ namespace FlaxEditor.GUI.ContextMenu
// Draw icon
const float iconSize = 14;
var icon = Checked ? Style.Current.CheckBoxTick : Icon;
var icon = Checked ? style.CheckBoxTick : Icon;
if (icon.IsValid)
Render2D.DrawSprite(icon, new Rectangle(-iconSize - 1, (Height - iconSize) / 2, iconSize, iconSize), textColor);
}

View File

@@ -50,14 +50,9 @@ namespace FlaxEditor.GUI
{
if (toolstrip == null)
return;
var lastToolstripButton = toolstrip.LastButton;
var parentSize = Parent.Size;
Bounds = new Rectangle
(
new Float2(lastToolstripButton.Right + 8.0f, 0),
new Float2(parentSize.X - X - 8.0f, toolstrip.Height)
);
Bounds = new Rectangle(lastToolstripButton.Right + 8.0f, 0, parentSize.X - X - 8.0f, toolstrip.Height);
}
}
}

View File

@@ -902,6 +902,23 @@ namespace FlaxEditor.Modules
}
if (sortChildren)
node.SortChildren();
// Ignore some special folders
if (node is MainContentTreeNode mainNode && mainNode.Folder.ShortName == "Source")
{
var mainNodeChild = mainNode.Folder.Find(StringUtils.CombinePaths(mainNode.Path, "obj")) as ContentFolder;
if (mainNodeChild != null)
{
mainNodeChild.Visible = false;
mainNodeChild.Node.Visible = false;
}
mainNodeChild = mainNode.Folder.Find(StringUtils.CombinePaths(mainNode.Path, "Properties")) as ContentFolder;
if (mainNodeChild != null)
{
mainNodeChild.Visible = false;
mainNodeChild.Node.Visible = false;
}
}
}
private void LoadScripts(ContentTreeNode parent, string[] files)

View File

@@ -202,6 +202,13 @@ namespace FlaxEditor.Windows
button.PerformLayout();
x += button.Width + NavigationBar.DefaultButtonsMargin;
_navigationBar.AddChild(button);
if (i > 0)
{
var separator = new ContentNavigationSeparator(button, x, ToolStrip.DefaultMarginV, h);
separator.PerformLayout();
x += separator.Width + NavigationBar.DefaultButtonsMargin;
_navigationBar.AddChild(separator);
}
}
nodes.Clear();
@@ -218,21 +225,13 @@ namespace FlaxEditor.Windows
/// <summary>
/// Gets the current view folder.
/// </summary>
public ContentFolder CurrentViewFolder
{
get
{
var node = SelectedNode;
return node?.Folder;
}
}
public ContentFolder CurrentViewFolder => SelectedNode?.Folder;
/// <summary>
/// Shows the root folder.
/// </summary>
public void ShowRoot()
{
// Show root folder
_tree.Select(_root);
}
}

View File

@@ -191,6 +191,7 @@ namespace FlaxEditor.Windows
}
// Search by filter only
bool showAllFiles = _showAllFiles;
if (string.IsNullOrWhiteSpace(query))
{
if (SelectedNode == _root)
@@ -199,12 +200,12 @@ namespace FlaxEditor.Windows
for (int i = 0; i < _root.ChildrenCount; i++)
{
if (_root.GetChild(i) is ContentTreeNode node)
UpdateItemsSearchFilter(node.Folder, items, filters);
UpdateItemsSearchFilter(node.Folder, items, filters, showAllFiles);
}
}
else
{
UpdateItemsSearchFilter(CurrentViewFolder, items, filters);
UpdateItemsSearchFilter(CurrentViewFolder, items, filters, showAllFiles);
}
}
// Search by asset ID
@@ -221,12 +222,12 @@ namespace FlaxEditor.Windows
for (int i = 0; i < _root.ChildrenCount; i++)
{
if (_root.GetChild(i) is ContentTreeNode node)
UpdateItemsSearchFilter(node.Folder, items, filters, query);
UpdateItemsSearchFilter(node.Folder, items, filters, showAllFiles, query);
}
}
else
{
UpdateItemsSearchFilter(CurrentViewFolder, items, filters, query);
UpdateItemsSearchFilter(CurrentViewFolder, items, filters, showAllFiles, query);
}
}
@@ -234,42 +235,34 @@ namespace FlaxEditor.Windows
_view.ShowItems(items, _sortType);
}
private void UpdateItemsSearchFilter(ContentFolder folder, List<ContentItem> items, bool[] filters)
private void UpdateItemsSearchFilter(ContentFolder folder, List<ContentItem> items, bool[] filters, bool showAllFiles)
{
for (int i = 0; i < folder.Children.Count; i++)
{
var child = folder.Children[i];
if (child is ContentFolder childFolder)
{
UpdateItemsSearchFilter(childFolder, items, filters);
UpdateItemsSearchFilter(childFolder, items, filters, showAllFiles);
}
else
else if (filters[(int)child.SearchFilter] && (showAllFiles || !(child is FileItem)))
{
if (filters[(int)child.SearchFilter])
{
items.Add(child);
}
items.Add(child);
}
}
}
private void UpdateItemsSearchFilter(ContentFolder folder, List<ContentItem> items, bool[] filters, string filterText)
private void UpdateItemsSearchFilter(ContentFolder folder, List<ContentItem> items, bool[] filters, bool showAllFiles, string filterText)
{
for (int i = 0; i < folder.Children.Count; i++)
{
var child = folder.Children[i];
if (child is ContentFolder childFolder)
{
UpdateItemsSearchFilter(childFolder, items, filters, filterText);
UpdateItemsSearchFilter(childFolder, items, filters, showAllFiles, filterText);
}
else if (filters[(int)child.SearchFilter])
else if (filters[(int)child.SearchFilter] && (showAllFiles || !(child is FileItem)) && QueryFilterHelper.Match(filterText, child.ShortName))
{
if (filters[(int)child.SearchFilter] && QueryFilterHelper.Match(filterText, child.ShortName))
{
items.Add(child);
}
items.Add(child);
}
}
}

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.Content.GUI;
@@ -45,6 +46,7 @@ namespace FlaxEditor.Windows
private TextBox _itemsSearchBox;
private ViewDropdown _viewDropdown;
private SortType _sortType;
private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true;
private RootContentTreeNode _root;
@@ -64,6 +66,57 @@ namespace FlaxEditor.Windows
/// </summary>
public ContentView View => _view;
internal bool ShowEngineFiles
{
get => _showEngineFiles;
set
{
if (_showEngineFiles != value)
{
_showEngineFiles = value;
if (Editor.ContentDatabase.Engine != null)
{
Editor.ContentDatabase.Engine.Visible = value;
Editor.ContentDatabase.Engine.Folder.Visible = value;
RefreshView();
}
}
}
}
internal bool ShowPluginsFiles
{
get => _showPluginsFiles;
set
{
if (_showPluginsFiles != value)
{
_showPluginsFiles = value;
foreach (var project in Editor.ContentDatabase.Projects)
{
if (project == Editor.ContentDatabase.Game || project == Editor.ContentDatabase.Engine)
continue;
project.Visible = value;
project.Folder.Visible = value;
RefreshView();
}
}
}
}
internal bool ShowAllFiles
{
get => _showAllFiles;
set
{
if (_showAllFiles != value)
{
_showAllFiles = value;
RefreshView();
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentWindow"/> class.
/// </summary>
@@ -107,11 +160,12 @@ namespace FlaxEditor.Windows
_navigateBackwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Left64, NavigateBackward).LinkTooltip("Navigate backward");
_navigateForwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Right64, NavigateForward).LinkTooltip("Navigate forward");
_navigateUpButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Up64, NavigateUp).LinkTooltip("Navigate up");
_toolStrip.AddSeparator();
// Navigation bar
_navigationBar = new NavigationBar
{
Parent = this,
Parent = _toolStrip,
};
// Split panel
@@ -216,10 +270,6 @@ namespace FlaxEditor.Windows
{
var menu = new ContextMenu();
var showFileExtensionsButton = menu.AddButton("Show file extensions", () => View.ShowFileExtensions = !View.ShowFileExtensions);
showFileExtensionsButton.Checked = View.ShowFileExtensions;
showFileExtensionsButton.AutoCheck = true;
var viewScale = menu.AddButton("View Scale");
viewScale.CloseMenuOnClick = false;
var scaleValue = new FloatValueBox(1, 75, 2, 50.0f, 0.3f, 3.0f, 0.01f)
@@ -243,6 +293,33 @@ namespace FlaxEditor.Windows
}
};
var show = menu.AddChildMenu("Show");
{
var b = show.ContextMenu.AddButton("File extensions", () => View.ShowFileExtensions = !View.ShowFileExtensions);
b.TooltipText = "Shows all files with extensions";
b.Checked = View.ShowFileExtensions;
b.CloseMenuOnClick = false;
b.AutoCheck = true;
b = show.ContextMenu.AddButton("Engine files", () => ShowEngineFiles = !ShowEngineFiles);
b.TooltipText = "Shows in-built engine content";
b.Checked = ShowEngineFiles;
b.CloseMenuOnClick = false;
b.AutoCheck = true;
b = show.ContextMenu.AddButton("Plugins files", () => ShowPluginsFiles = !ShowPluginsFiles);
b.TooltipText = "Shows plugin projects content";
b.Checked = ShowPluginsFiles;
b.CloseMenuOnClick = false;
b.AutoCheck = true;
b = show.ContextMenu.AddButton("All files", () => ShowAllFiles = !ShowAllFiles);
b.TooltipText = "Shows all files including other than assets and source code";
b.Checked = ShowAllFiles;
b.CloseMenuOnClick = false;
b.AutoCheck = true;
}
var filters = menu.AddChildMenu("Filters");
for (int i = 0; i < _viewDropdown.Items.Count; i++)
{
@@ -351,7 +428,7 @@ namespace FlaxEditor.Windows
{
if (!item.CanRename)
return;
// Show element in the view
Select(item, true);
@@ -428,10 +505,7 @@ namespace FlaxEditor.Windows
if (!Editor.ContentEditing.IsValidAssetName(item, newShortName, out string hint))
{
// Invalid name
MessageBox.Show("Given asset name is invalid. " + hint,
"Invalid name",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
MessageBox.Show("Given asset name is invalid. " + hint, "Invalid name", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
@@ -877,7 +951,7 @@ namespace FlaxEditor.Windows
if (target == _root)
{
// Special case for root folder
List<ContentItem> items = new List<ContentItem>(8);
var items = new List<ContentItem>(8);
for (int i = 0; i < _root.ChildrenCount; i++)
{
if (_root.GetChild(i) is ContentTreeNode node)
@@ -890,7 +964,10 @@ namespace FlaxEditor.Windows
else
{
// Show folder contents
_view.ShowItems(target.Folder.Children, _sortType, false, true);
var items = target.Folder.Children;
if (!_showAllFiles)
items = items.Where(x => !(x is FileItem)).ToList();
_view.ShowItems(items, _sortType, false, true);
}
}
@@ -913,12 +990,6 @@ namespace FlaxEditor.Windows
_navigateUpButton.Enabled = folder != null && _tree.SelectedNode != _root;
}
private void RemoveFolder2Root(ContentTreeNode node)
{
// Remove from the root
_root.RemoveChild(node);
}
/// <inheritdoc />
public override void OnInit()
{
@@ -937,8 +1008,12 @@ namespace FlaxEditor.Windows
project.SortChildrenRecursive();
if (project == Editor.ContentDatabase.Game || project == Editor.ContentDatabase.Engine)
continue;
project.Visible = _showPluginsFiles;
project.Folder.Visible = _showPluginsFiles;
_root.AddChild(project);
}
Editor.ContentDatabase.Engine.Visible = _showEngineFiles;
Editor.ContentDatabase.Engine.Folder.Visible = _showEngineFiles;
_root.AddChild(Editor.ContentDatabase.Engine);
Editor.ContentDatabase.Game?.Expand(true);
@@ -1010,7 +1085,6 @@ namespace FlaxEditor.Windows
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
// Check if it's a right mouse button
if (button == MouseButton.Right)
{
// Find control that is under the mouse
@@ -1066,6 +1140,9 @@ namespace FlaxEditor.Windows
LayoutSerializeSplitter(writer, "Split", _split);
writer.WriteAttributeString("Scale", _view.ViewScale.ToString(CultureInfo.InvariantCulture));
writer.WriteAttributeString("ShowFileExtensions", _view.ShowFileExtensions.ToString());
writer.WriteAttributeString("ShowEngineFiles", ShowEngineFiles.ToString());
writer.WriteAttributeString("ShowPluginsFiles", ShowPluginsFiles.ToString());
writer.WriteAttributeString("ShowAllFiles", ShowAllFiles.ToString());
writer.WriteAttributeString("ViewType", _view.ViewType.ToString());
}
@@ -1077,6 +1154,12 @@ namespace FlaxEditor.Windows
_view.ViewScale = value1;
if (bool.TryParse(node.GetAttribute("ShowFileExtensions"), out bool value2))
_view.ShowFileExtensions = value2;
if (bool.TryParse(node.GetAttribute("ShowEngineFiles"), out value2))
ShowEngineFiles = value2;
if (bool.TryParse(node.GetAttribute("ShowPluginsFiles"), out value2))
ShowPluginsFiles = value2;
if (bool.TryParse(node.GetAttribute("ShowAllFiles"), out value2))
ShowAllFiles = value2;
if (Enum.TryParse(node.GetAttribute("ViewType"), out ContentViewType viewType))
_view.ViewType = viewType;
}