A game framework written with osu! in mind.
at master 87 lines 2.9 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Collections.Generic; 6using System.Linq; 7using osu.Framework.Caching; 8using osu.Framework.Extensions.IEnumerableExtensions; 9 10namespace osu.Framework.Graphics.Containers 11{ 12 public class SearchContainer : SearchContainer<Drawable> 13 { 14 } 15 16 /// <summary> 17 /// A container which filters children based on a search term. 18 /// Re-filtering will only be performed when the <see cref="SearchTerm"/> changes, or 19 /// new items are added as direct children of this container. 20 /// </summary> 21 /// <typeparam name="T"></typeparam> 22 public class SearchContainer<T> : FillFlowContainer<T> where T : Drawable 23 { 24 private string searchTerm; 25 26 /// <summary> 27 /// A string that should match the <see cref="IFilterable"/> children 28 /// </summary> 29 public string SearchTerm 30 { 31 get => searchTerm; 32 set 33 { 34 if (value == searchTerm) 35 return; 36 37 searchTerm = value; 38 filterValid.Invalidate(); 39 } 40 } 41 42 protected internal override void AddInternal(Drawable drawable) 43 { 44 base.AddInternal(drawable); 45 filterValid.Invalidate(); 46 } 47 48 private readonly Cached filterValid = new Cached(); 49 50 protected override void Update() 51 { 52 base.Update(); 53 54 if (!filterValid.IsValid) 55 { 56 performFilter(); 57 filterValid.Validate(); 58 } 59 } 60 61 private void performFilter() 62 { 63 var terms = (searchTerm ?? string.Empty).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 64 Children.OfType<IFilterable>().ForEach(child => match(child, terms, terms.Length > 0)); 65 } 66 67 private static bool match(IFilterable filterable, IEnumerable<string> terms, bool searchActive) 68 { 69 //Words matched by parent is not needed to match children 70 var childTerms = terms.Where(term => 71 !filterable.FilterTerms.Any(filterTerm => 72 filterTerm.Contains(term, StringComparison.InvariantCultureIgnoreCase))).ToArray(); 73 74 bool matching = childTerms.Length == 0; 75 76 //We need to check the children and should any child match this matches as well 77 if (filterable is IHasFilterableChildren hasFilterableChildren) 78 { 79 foreach (IFilterable child in hasFilterableChildren.FilterableChildren) 80 matching |= match(child, childTerms, searchActive); 81 } 82 83 filterable.FilteringActive = searchActive; 84 return filterable.MatchingFilter = matching; 85 } 86 } 87}