UnityGame/Library/PackageCache/com.unity.searcher/Editor/Searcher/SearcherAdapter.cs
2024-10-27 10:53:47 +03:00

129 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Searcher
{
public enum ItemExpanderState
{
Hidden,
Collapsed,
Expanded
}
[PublicAPI]
public interface ISearcherAdapter
{
VisualElement MakeItem();
VisualElement Bind(VisualElement target, SearcherItem item, ItemExpanderState expanderState, string text);
string Title { get; }
bool HasDetailsPanel { get; }
bool AddAllChildResults { get; }
bool MultiSelectEnabled { get; }
float InitialSplitterDetailRatio { get; }
void OnSelectionChanged(IEnumerable<SearcherItem> items);
SearcherItem OnSearchResultsFilter(IEnumerable<SearcherItem> searchResults, string searchQuery);
void InitDetailsPanel(VisualElement detailsPanel);
}
[PublicAPI]
public class SearcherAdapter : ISearcherAdapter
{
const string k_EntryName = "smartSearchItem";
const int k_IndentDepthFactor = 15;
readonly VisualTreeAsset m_DefaultItemTemplate;
public virtual string Title { get; }
public virtual bool HasDetailsPanel => true;
public virtual bool AddAllChildResults => true;
public virtual bool MultiSelectEnabled => false;
Label m_DetailsLabel;
public virtual float InitialSplitterDetailRatio => 1.0f;
public SearcherAdapter(string title)
{
Title = title;
m_DefaultItemTemplate = Resources.Load<VisualTreeAsset>("SearcherItem");
}
public virtual VisualElement MakeItem()
{
// Create a visual element hierarchy for this search result.
var item = m_DefaultItemTemplate.CloneTree();
return item;
}
public virtual VisualElement Bind(VisualElement element, SearcherItem item, ItemExpanderState expanderState, string query)
{
var indent = element.Q<VisualElement>("itemIndent");
indent.style.width = item.Depth * k_IndentDepthFactor;
var expander = element.Q<VisualElement>("itemChildExpander");
var icon = expander.Query("expanderIcon").First();
icon.ClearClassList();
switch (expanderState)
{
case ItemExpanderState.Expanded:
icon.AddToClassList("Expanded");
break;
case ItemExpanderState.Collapsed:
icon.AddToClassList("Collapsed");
break;
}
var nameLabelsContainer = element.Q<VisualElement>("labelsContainer");
nameLabelsContainer.Clear();
var iconElement = element.Q<VisualElement>("itemIconVisualElement");
iconElement.style.backgroundImage = item.Icon;
if (item.Icon == null && item.CollapseEmptyIcon)
{
iconElement.style.display = DisplayStyle.None;
} else
{
iconElement.style.display = DisplayStyle.Flex;
}
if (string.IsNullOrWhiteSpace(query))
nameLabelsContainer.Add(new Label(item.Name));
else
SearcherHighlighter.HighlightTextBasedOnQuery(nameLabelsContainer, item.Name, query);
element.userData = item;
element.name = k_EntryName;
return expander;
}
public virtual void InitDetailsPanel(VisualElement detailsPanel)
{
m_DetailsLabel = new Label();
detailsPanel.Add(m_DetailsLabel);
}
public virtual void OnSelectionChanged(IEnumerable<SearcherItem> items)
{
if (m_DetailsLabel != null)
{
var itemsList = items.ToList();
m_DetailsLabel.text = itemsList.Any() ? itemsList[0].Help : "No results";
}
}
// How to handle filtering and prioritization of search results is specific to clients of the searcher window
// This callback is meant to be implemented by child classes of SearcherAdapter as they need
public virtual SearcherItem OnSearchResultsFilter(IEnumerable<SearcherItem> searchResults, string searchQuery)
{
return new SearcherItem("");
}
}
}