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 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 ); } }