Files
sbox-public/game/addons/tools/Code/Editor/AssetBrowser/SearchWidget.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

277 lines
5.7 KiB
C#

using System.IO;
using System.Threading;
namespace Editor;
public class SearchWidget : Widget
{
private LineEdit LineEdit;
private ToolButton ClearButton;
public string Value
{
get => LineEdit.Value;
set
{
LineEdit.Value = value;
Update();
}
}
public string BaseQuery { get; set; } = string.Empty;
public string Query => $"{BaseQuery} {Value}".TrimStart();
public Action ValueChanged;
public TagPicker AssetTypes;
public bool IsEmpty => string.IsNullOrEmpty( Query );
public SearchWidget( Widget parent, bool showAssetTypes = true ) : base( parent )
{
Layout = Layout.Row();
Layout.Alignment = TextFlag.LeftCenter;
LineEdit = Layout.Add( new LineEdit(), 1 );
LineEdit.PlaceholderText = $"⌕ Search";
LineEdit.TextChanged += OnTextChanged;
if ( parent is AssetBrowser ab )
{
LineEdit.PlaceholderText = $"⌕ Search {ab.CurrentLocation?.Name}";
ab.OnFolderOpened = () =>
{
LineEdit.PlaceholderText = $"⌕ Search {ab.CurrentLocation?.Name}";
LineEdit.Update();
};
}
ClearButton = Layout.Add( new ToolButton( string.Empty, "clear", this ) );
ClearButton.Visible = false;
ClearButton.MouseLeftPress = () =>
{
LineEdit.Text = string.Empty;
};
if ( showAssetTypes )
{
AssetTypes = new TagPicker();
AssetTypes.Icon = "filter_list";
AssetTypes.OnValueChanged = () =>
{
ValueChanged?.Invoke();
Update();
};
Layout.Add( AssetTypes );
}
}
private void OnTextChanged( string value )
{
if ( value.EndsWith( " " ) )
{
var split = value.Split( " " ).ToList();
bool splitChanged = false;
foreach ( var s in split.ToArray() )
{
if ( s.StartsWith( "t:" ) )
{
var typeName = s[2..].Trim();
if ( string.IsNullOrWhiteSpace( typeName ) )
continue;
AssetTypes.Toggle( typeName );
split.Remove( s );
splitChanged = true;
}
}
if ( splitChanged )
LineEdit.Text = string.Join( " ", split );
}
ClearButton.Visible = !string.IsNullOrEmpty( value );
ValueChanged?.Invoke();
}
public IEnumerable<FileInfo> Filter( LocalAssetBrowser.Location location, CancellationToken token, bool showRecursiveFiles = false )
{
if ( token.IsCancellationRequested )
yield break;
foreach ( var file in location.GetFiles() )
{
if ( token.IsCancellationRequested )
yield break;
if ( FilterName( file ) )
continue;
if ( FilterAssetTags( file ) )
continue;
if ( FilterAssetType( file ) )
continue;
yield return file;
}
if ( showRecursiveFiles )
{
foreach ( var subDir in location.GetDirectories() )
{
if ( token.IsCancellationRequested )
yield break;
foreach ( var subFile in Filter( subDir, token, showRecursiveFiles ) )
{
if ( token.IsCancellationRequested )
yield break;
yield return subFile;
}
}
}
}
private bool FilterName( FileInfo file )
{
if ( IsEmpty )
return false;
var asset = AssetSystem.FindByPath( file.FullName );
var query = Query;
var splitValues = query.Split( " " );
bool hasExtension = query.Contains( '.' );
if ( asset != null && !hasExtension )
{
foreach ( var splitValue in splitValues )
{
var search = splitValue;
var negated = false;
if ( splitValue.StartsWith( "-" ) )
{
search = splitValue.Substring( 1 );
negated = true;
}
var assetName = asset.Name;
if ( AssetLocations.IncludePathNames )
{
assetName = asset.RelativePath;
}
if ( !negated )
{
if ( !(
assetName.Contains( search, StringComparison.OrdinalIgnoreCase )
|| asset.AssetType.FriendlyName.Contains( search, StringComparison.OrdinalIgnoreCase )
|| asset.Tags.Any( x => x.Contains( search, StringComparison.OrdinalIgnoreCase ) )
) )
{
return true;
}
}
else
{
if ( assetName.Contains( search, StringComparison.OrdinalIgnoreCase )
|| asset.AssetType.FriendlyName.Contains( search, StringComparison.OrdinalIgnoreCase )
|| asset.Tags.Any( x => x.Contains( search, StringComparison.OrdinalIgnoreCase ) ) )
{
return true;
}
}
}
return false;
}
else
{
// Loose file filtering
foreach ( var splitValue in splitValues )
{
var search = splitValue;
var negated = false;
if ( splitValue.StartsWith( "-" ) )
{
search = splitValue.Substring( 1 );
negated = true;
}
if ( !negated )
{
if ( !file.Name.Contains( search, StringComparison.OrdinalIgnoreCase ) )
{
return true;
}
}
else
{
if ( file.Name.Contains( search, StringComparison.OrdinalIgnoreCase ) )
{
return true;
}
}
}
return false;
}
}
private bool FilterAssetType( FileInfo file )
{
var types = AssetTypes.ActiveTags.Where( x => !x.StartsWith( "tag:" ) );
if ( types.Count() == 0 )
return false;
if ( string.IsNullOrWhiteSpace( file.Extension ) )
return false;
var ext = file.Extension.Substring( 1 ); // trim dot
foreach ( var typeExt in types )
{
if ( ext.Equals( typeExt, StringComparison.OrdinalIgnoreCase ) || ext.Equals( $"{typeExt}_c", StringComparison.OrdinalIgnoreCase ) )
{
return false;
}
}
return true; // remove
}
private bool FilterAssetTags( FileInfo file )
{
var tags = AssetTypes.ActiveTags.Where( x => x.StartsWith( "tag:" ) );
if ( tags.Count() == 0 )
return false;
var asset = AssetSystem.FindByPath( file.FullName );
if ( asset is null )
return true;
foreach ( var e in tags )
{
string tag = e[4..];
return !asset?.Tags.Any( x => x == tag ) ?? true;
}
return true; // remove
}
protected override void OnPaint()
{
Paint.ClearBrush();
Paint.ClearPen();
var rect = LocalRect;
Paint.SetBrush( Theme.ControlBackground );
Paint.DrawRect( rect, Theme.ControlRadius );
}
}