Reorganize Content Finder files
This commit is contained in:
245
Source/Editor/Windows/Search/ContentFinder.cs
Normal file
245
Source/Editor/Windows/Search/ContentFinder.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Modules;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Windows.Search
|
||||
{
|
||||
/// <summary>
|
||||
/// The content finder popup. Allows to search for project items and quickly navigate to.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.GUI.ContextMenu.ContextMenuBase" />
|
||||
[HideInEditor]
|
||||
public class ContentFinder : ContextMenuBase
|
||||
{
|
||||
private Panel _resultPanel;
|
||||
private TextBox _searchBox;
|
||||
private SearchItem _selectedItem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height per item.
|
||||
/// </summary>
|
||||
public float ItemHeight { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of item to show.
|
||||
/// </summary>
|
||||
public int VisibleItemCount { get; set; } = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item.
|
||||
/// </summary>
|
||||
public SearchItem SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
if (value == _selectedItem || (value != null && !MatchedItems.Contains(value)))
|
||||
return;
|
||||
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
_selectedItem.BackgroundColor = Color.Transparent;
|
||||
}
|
||||
|
||||
_selectedItem = value;
|
||||
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
_selectedItem.BackgroundColor = Style.Current.BackgroundSelected;
|
||||
|
||||
if (MatchedItems.Count > VisibleItemCount)
|
||||
{
|
||||
_resultPanel.VScrollBar.SmoothingScale = 0;
|
||||
_resultPanel.ScrollViewTo(_selectedItem);
|
||||
_resultPanel.VScrollBar.SmoothingScale = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets actual matched item list.
|
||||
/// </summary>
|
||||
public List<SearchItem> MatchedItems { get; } = new List<SearchItem>();
|
||||
|
||||
internal bool Hand;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentFinder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="width">The finder width.</param>
|
||||
public ContentFinder(float width = 440.0f)
|
||||
{
|
||||
Size = new Vector2(width, TextBox.DefaultHeight + 2.0f);
|
||||
|
||||
_searchBox = new TextBox
|
||||
{
|
||||
X = 1,
|
||||
Y = 1,
|
||||
Width = width - 2.0f,
|
||||
WatermarkText = "Type to search...",
|
||||
Parent = this
|
||||
};
|
||||
_searchBox.TextChanged += OnTextChanged;
|
||||
|
||||
_resultPanel = new Panel
|
||||
{
|
||||
Location = new Vector2(1, _searchBox.Height + 1),
|
||||
Size = new Vector2(width - 2.0f, Height - (_searchBox.Height + 1 + 1)),
|
||||
Parent = this
|
||||
};
|
||||
}
|
||||
|
||||
private void OnTextChanged()
|
||||
{
|
||||
MatchedItems.Clear();
|
||||
SelectedItem = null;
|
||||
|
||||
var results = Editor.Instance.ContentFinding.Search(_searchBox.Text);
|
||||
BuildList(results);
|
||||
}
|
||||
|
||||
private void BuildList(List<SearchResult> items)
|
||||
{
|
||||
_resultPanel.DisposeChildren();
|
||||
LockChildrenRecursive();
|
||||
|
||||
var dpiScale = DpiScale;
|
||||
var window = RootWindow.Window;
|
||||
|
||||
if (items.Count == 0)
|
||||
{
|
||||
Height = _searchBox.Height + 1;
|
||||
_resultPanel.ScrollBars = ScrollBars.None;
|
||||
window.ClientSize = new Vector2(window.ClientSize.X, Height * dpiScale);
|
||||
UnlockChildrenRecursive();
|
||||
PerformLayout();
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup items container
|
||||
if (items.Count <= VisibleItemCount)
|
||||
{
|
||||
Height = 1 + _searchBox.Height + 1 + ItemHeight * items.Count;
|
||||
_resultPanel.ScrollBars = ScrollBars.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
Height = 1 + _searchBox.Height + 1 + ItemHeight * VisibleItemCount;
|
||||
_resultPanel.ScrollBars = ScrollBars.Vertical;
|
||||
}
|
||||
|
||||
_resultPanel.Height = ItemHeight * VisibleItemCount;
|
||||
var itemsWidth = _resultPanel.GetClientArea().Width;
|
||||
var itemHeight = ItemHeight;
|
||||
|
||||
// Spawn items
|
||||
for (var i = 0; i < items.Count; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
SearchItem searchItem;
|
||||
if (item.Item is AssetItem assetItem)
|
||||
searchItem = new AssetSearchItem(item.Name, item.Type, assetItem, this, itemsWidth, itemHeight);
|
||||
else
|
||||
searchItem = new SearchItem(item.Name, item.Type, item.Item, this, itemsWidth, itemHeight);
|
||||
searchItem.Y = i * itemHeight;
|
||||
searchItem.Parent = _resultPanel;
|
||||
MatchedItems.Add(searchItem);
|
||||
}
|
||||
|
||||
window.ClientSize = new Vector2(window.ClientSize.X, Height * dpiScale);
|
||||
|
||||
UnlockChildrenRecursive();
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Show(Control parent, Vector2 location)
|
||||
{
|
||||
base.Show(parent, location);
|
||||
|
||||
// Setup
|
||||
_resultPanel.ScrollViewTo(Vector2.Zero);
|
||||
_searchBox.Text = string.Empty;
|
||||
_searchBox.Focus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float delta)
|
||||
{
|
||||
Hand = false;
|
||||
|
||||
base.Update(delta);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KeyboardKeys.ArrowDown:
|
||||
{
|
||||
if (MatchedItems.Count == 0)
|
||||
return true;
|
||||
int currentPos;
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
currentPos = MatchedItems.IndexOf(_selectedItem) + 1;
|
||||
if (currentPos >= MatchedItems.Count)
|
||||
currentPos--;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPos = 0;
|
||||
}
|
||||
SelectedItem = MatchedItems[currentPos];
|
||||
return true;
|
||||
}
|
||||
case KeyboardKeys.ArrowUp:
|
||||
{
|
||||
if (MatchedItems.Count == 0)
|
||||
return true;
|
||||
int currentPos;
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
currentPos = MatchedItems.IndexOf(_selectedItem) - 1;
|
||||
if (currentPos < 0)
|
||||
currentPos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPos = 0;
|
||||
}
|
||||
SelectedItem = MatchedItems[currentPos];
|
||||
return true;
|
||||
}
|
||||
case KeyboardKeys.Return:
|
||||
{
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
Hide();
|
||||
Editor.Instance.ContentFinding.Open(_selectedItem.Item);
|
||||
}
|
||||
else if (_selectedItem == null && _searchBox.TextLength != 0 && MatchedItems.Count != 0)
|
||||
{
|
||||
Hide();
|
||||
Editor.Instance.ContentFinding.Open(MatchedItems[0].Item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case KeyboardKeys.Escape:
|
||||
{
|
||||
Hide();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
239
Source/Editor/Windows/Search/SearchItem.cs
Normal file
239
Source/Editor/Windows/Search/SearchItem.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Windows.Search
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ContentFinder"/> item.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public class SearchItem : ContainerControl
|
||||
{
|
||||
private ContentFinder _finder;
|
||||
|
||||
/// <summary>
|
||||
/// The item icon.
|
||||
/// </summary>
|
||||
protected Image _icon;
|
||||
|
||||
/// <summary>
|
||||
/// The item name.
|
||||
/// </summary>
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// The item type name.
|
||||
/// </summary>
|
||||
public string Type;
|
||||
|
||||
/// <summary>
|
||||
/// The item object reference.
|
||||
/// </summary>
|
||||
public object Item;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SearchItem"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="finder">The finder.</param>
|
||||
/// <param name="width">The item width.</param>
|
||||
/// <param name="height">The item height.</param>
|
||||
public SearchItem(string name, string type, object item, ContentFinder finder, float width, float height)
|
||||
{
|
||||
Size = new Vector2(width, height);
|
||||
Name = name;
|
||||
Type = type;
|
||||
Item = item;
|
||||
_finder = finder;
|
||||
|
||||
var logoSize = 15.0f;
|
||||
var icon = new Image
|
||||
{
|
||||
Size = new Vector2(logoSize),
|
||||
Location = new Vector2(5, (height - logoSize) / 2)
|
||||
};
|
||||
_icon = icon;
|
||||
|
||||
var nameLabel = AddChild<Label>();
|
||||
nameLabel.Height = 25;
|
||||
nameLabel.Location = new Vector2(icon.X + icon.Width + 5, (height - nameLabel.Height) / 2);
|
||||
nameLabel.Text = Name;
|
||||
nameLabel.HorizontalAlignment = TextAlignment.Near;
|
||||
|
||||
var typeLabel = AddChild<Label>();
|
||||
typeLabel.Height = 25;
|
||||
typeLabel.Location = new Vector2((height - nameLabel.Height) / 2, X + width - typeLabel.Width - 17);
|
||||
typeLabel.HorizontalAlignment = TextAlignment.Far;
|
||||
typeLabel.Text = Type;
|
||||
typeLabel.TextColor = Style.Current.ForegroundGrey;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
_finder.Hide();
|
||||
Editor.Instance.ContentFinding.Open(Item);
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseEnter(Vector2 location)
|
||||
{
|
||||
base.OnMouseEnter(location);
|
||||
|
||||
var root = RootWindow;
|
||||
if (root != null)
|
||||
{
|
||||
root.Cursor = CursorType.Hand;
|
||||
}
|
||||
|
||||
_finder.SelectedItem = this;
|
||||
_finder.Hand = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
Item = null;
|
||||
_finder = null;
|
||||
_icon = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="SearchItem"/> for assets. Supports using asset thumbnail.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Windows.Search.SearchItem" />
|
||||
/// <seealso cref="FlaxEditor.Content.IContentItemOwner" />
|
||||
public class AssetSearchItem : SearchItem, IContentItemOwner
|
||||
{
|
||||
private AssetItem _asset;
|
||||
private FlaxEditor.GUI.ContextMenu.ContextMenu _cm;
|
||||
|
||||
/// <inheritdoc />
|
||||
public AssetSearchItem(string name, string type, AssetItem item, ContentFinder finder, float width, float height)
|
||||
: base(name, type, item, finder, width, height)
|
||||
{
|
||||
_asset = item;
|
||||
_asset.AddReference(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool ShowTooltip => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnShowTooltip(out string text, out Vector2 location, out Rectangle area)
|
||||
{
|
||||
if (string.IsNullOrEmpty(TooltipText) && Item is AssetItem assetItem)
|
||||
{
|
||||
assetItem.UpdateTooltipText();
|
||||
TooltipText = assetItem.TooltipText;
|
||||
}
|
||||
return base.OnShowTooltip(out text, out location, out area);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseUp(location, button))
|
||||
return true;
|
||||
if (button == MouseButton.Right && Item is AssetItem assetItem)
|
||||
{
|
||||
// Show context menu
|
||||
var proxy = Editor.Instance.ContentDatabase.GetProxy(assetItem);
|
||||
ContextMenuButton b;
|
||||
var cm = new FlaxEditor.GUI.ContextMenu.ContextMenu { Tag = assetItem };
|
||||
b = cm.AddButton("Open", () => Editor.Instance.ContentFinding.Open(Item));
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
|
||||
cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem, true));
|
||||
b.Enabled = proxy != null && proxy.CanReimport(assetItem);
|
||||
if (assetItem is BinaryAssetItem binaryAsset)
|
||||
{
|
||||
if (!binaryAsset.GetImportPath(out string importPath))
|
||||
{
|
||||
string importLocation = System.IO.Path.GetDirectoryName(importPath);
|
||||
if (!string.IsNullOrEmpty(importLocation) && System.IO.Directory.Exists(importLocation))
|
||||
{
|
||||
cm.AddButton("Show import location", () => FileSystem.ShowFileExplorer(importLocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Copy asset ID", () => Clipboard.Text = FlaxEngine.Json.JsonSerializer.GetStringID(assetItem.ID));
|
||||
cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID));
|
||||
cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem)));
|
||||
cm.AddSeparator();
|
||||
proxy?.OnContentWindowContextMenu(cm, assetItem);
|
||||
assetItem.OnContextMenu(cm);
|
||||
cm.AddButton("Copy name to Clipboard", () => Clipboard.Text = assetItem.NamePath);
|
||||
cm.AddButton("Copy path to Clipboard", () => Clipboard.Text = assetItem.Path);
|
||||
cm.Show(this, location);
|
||||
_cm = cm;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
// Draw context menu hint
|
||||
if (_cm != null && _cm.Visible)
|
||||
Render2D.FillRectangle(new Rectangle(Vector2.Zero, Size), Color.Gray);
|
||||
|
||||
base.Draw();
|
||||
|
||||
// Draw icon
|
||||
var iconRect = _icon.Bounds;
|
||||
_asset.DrawThumbnail(ref iconRect);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
_cm = null;
|
||||
if (_asset != null)
|
||||
{
|
||||
_asset.RemoveReference(this);
|
||||
_asset = null;
|
||||
}
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemDeleted(ContentItem item)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemRenamed(ContentItem item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemReimported(ContentItem item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemDispose(ContentItem item)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user