diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs index 23feb1466e..7cd4791acb 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs @@ -231,7 +231,7 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.Click(MouseButton.Left); }); - private IEnumerable.DropdownMenu.DrawableDropdownMenuItem> getCollectionDropdownItems() - => control.ChildrenOfType().Single().ChildrenOfType.DropdownMenu.DrawableDropdownMenuItem>(); + private IEnumerable.DropdownMenu.DrawableDropdownMenuItem> getCollectionDropdownItems() + => control.ChildrenOfType().Single().ChildrenOfType.DropdownMenu.DrawableDropdownMenuItem>(); } } diff --git a/osu.Game/Screens/Select/CollectionFilterDropdown.cs b/osu.Game/Collections/CollectionFilterDropdown.cs similarity index 82% rename from osu.Game/Screens/Select/CollectionFilterDropdown.cs rename to osu.Game/Collections/CollectionFilterDropdown.cs index b08c3b167d..ec0e9d5a89 100644 --- a/osu.Game/Screens/Select/CollectionFilterDropdown.cs +++ b/osu.Game/Collections/CollectionFilterDropdown.cs @@ -12,22 +12,26 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Beatmaps; -using osu.Game.Collections; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK; -namespace osu.Game.Screens.Select +namespace osu.Game.Collections { /// - /// A dropdown to select the to filter beatmaps using. + /// A dropdown to select the to filter beatmaps using. /// - public class CollectionFilterDropdown : OsuDropdown + public class CollectionFilterDropdown : OsuDropdown { + /// + /// Whether to show the "manage collections..." menu item in the dropdown. + /// + protected virtual bool ShowManageCollectionsItem => true; + private readonly IBindableList collections = new BindableList(); private readonly IBindableList beatmaps = new BindableList(); - private readonly BindableList filters = new BindableList(); + private readonly BindableList filters = new BindableList(); [Resolved(CanBeNull = true)] private ManageCollectionsDialog manageCollectionsDialog { get; set; } @@ -62,17 +66,19 @@ namespace osu.Game.Screens.Select var selectedItem = SelectedItem?.Value?.Collection; filters.Clear(); - filters.Add(new AllBeatmapsCollectionMenuItem()); - filters.AddRange(collections.Select(c => new CollectionMenuItem(c))); - filters.Add(new ManageCollectionsMenuItem()); + filters.Add(new AllBeatmapsCollectionFilterMenuItem()); + filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c))); + + if (ShowManageCollectionsItem) + filters.Add(new ManageCollectionsFilterMenuItem()); Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection == selectedItem) ?? filters[0]; } /// - /// Occurs when the selection has changed. + /// Occurs when the selection has changed. /// - private void filterChanged(ValueChangedEvent filter) + private void filterChanged(ValueChangedEvent filter) { // Binding the beatmaps will trigger a collection change event, which results in an infinite-loop. This is rebound later, when it's safe to do so. beatmaps.CollectionChanged -= filterBeatmapsChanged; @@ -87,7 +93,7 @@ namespace osu.Game.Screens.Select // Never select the manage collection filter - rollback to the previous filter. // This is done after the above since it is important that bindable is unbound from OldValue, which is lost after forcing it back to the old value. - if (filter.NewValue is ManageCollectionsMenuItem) + if (filter.NewValue is ManageCollectionsFilterMenuItem) { Current.Value = filter.OldValue; manageCollectionsDialog?.Show(); @@ -104,18 +110,22 @@ namespace osu.Game.Screens.Select Current.TriggerChange(); } - protected override string GenerateItemText(CollectionMenuItem item) => item.CollectionName.Value; + protected override string GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName.Value; - protected override DropdownHeader CreateHeader() => new CollectionDropdownHeader + protected sealed override DropdownHeader CreateHeader() => CreateCollectionHeader().With(d => { - SelectedItem = { BindTarget = Current } - }; + d.SelectedItem.BindTarget = Current; + }); - protected override DropdownMenu CreateMenu() => new CollectionDropdownMenu(); + protected sealed override DropdownMenu CreateMenu() => CreateCollectionMenu(); + + protected virtual CollectionDropdownHeader CreateCollectionHeader() => new CollectionDropdownHeader(); + + protected virtual CollectionDropdownMenu CreateCollectionMenu() => new CollectionDropdownMenu(); public class CollectionDropdownHeader : OsuDropdownHeader { - public readonly Bindable SelectedItem = new Bindable(); + public readonly Bindable SelectedItem = new Bindable(); private readonly Bindable collectionName = new Bindable(); protected override string Label @@ -152,7 +162,7 @@ namespace osu.Game.Screens.Select private void updateText() => base.Label = collectionName.Value; } - private class CollectionDropdownMenu : OsuDropdownMenu + protected class CollectionDropdownMenu : OsuDropdownMenu { public CollectionDropdownMenu() { @@ -162,10 +172,10 @@ namespace osu.Game.Screens.Select protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new CollectionDropdownMenuItem(item); } - private class CollectionDropdownMenuItem : OsuDropdownMenu.DrawableOsuDropdownMenuItem + protected class CollectionDropdownMenuItem : OsuDropdownMenu.DrawableOsuDropdownMenuItem { [NotNull] - protected new CollectionMenuItem Item => ((DropdownMenuItem)base.Item).Value; + protected new CollectionFilterMenuItem Item => ((DropdownMenuItem)base.Item).Value; [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game/Screens/Select/CollectionMenuItem.cs b/osu.Game/Collections/CollectionFilterMenuItem.cs similarity index 71% rename from osu.Game/Screens/Select/CollectionMenuItem.cs rename to osu.Game/Collections/CollectionFilterMenuItem.cs index 995651de19..4a489d2945 100644 --- a/osu.Game/Screens/Select/CollectionMenuItem.cs +++ b/osu.Game/Collections/CollectionFilterMenuItem.cs @@ -3,14 +3,13 @@ using JetBrains.Annotations; using osu.Framework.Bindables; -using osu.Game.Collections; -namespace osu.Game.Screens.Select +namespace osu.Game.Collections { /// /// A filter. /// - public class CollectionMenuItem + public class CollectionFilterMenuItem { /// /// The collection to filter beatmaps from. @@ -26,27 +25,27 @@ namespace osu.Game.Screens.Select public readonly Bindable CollectionName; /// - /// Creates a new . + /// Creates a new . /// /// The collection to filter beatmaps from. - public CollectionMenuItem([CanBeNull] BeatmapCollection collection) + public CollectionFilterMenuItem([CanBeNull] BeatmapCollection collection) { Collection = collection; CollectionName = Collection?.Name.GetBoundCopy() ?? new Bindable("All beatmaps"); } } - public class AllBeatmapsCollectionMenuItem : CollectionMenuItem + public class AllBeatmapsCollectionFilterMenuItem : CollectionFilterMenuItem { - public AllBeatmapsCollectionMenuItem() + public AllBeatmapsCollectionFilterMenuItem() : base(null) { } } - public class ManageCollectionsMenuItem : CollectionMenuItem + public class ManageCollectionsFilterMenuItem : CollectionFilterMenuItem { - public ManageCollectionsMenuItem() + public ManageCollectionsFilterMenuItem() : base(null) { CollectionName.Value = "Manage collections..."; diff --git a/osu.Game/Overlays/Music/CollectionsDropdown.cs b/osu.Game/Overlays/Music/CollectionDropdown.cs similarity index 72% rename from osu.Game/Overlays/Music/CollectionsDropdown.cs rename to osu.Game/Overlays/Music/CollectionDropdown.cs index 5bd321f31e..ed0ebf696b 100644 --- a/osu.Game/Overlays/Music/CollectionsDropdown.cs +++ b/osu.Game/Overlays/Music/CollectionDropdown.cs @@ -7,25 +7,29 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.UserInterface; +using osu.Game.Collections; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Music { - public class CollectionsDropdown : OsuDropdown + /// + /// A for use in the . + /// + public class CollectionDropdown : CollectionFilterDropdown { + protected override bool ShowManageCollectionsItem => false; + [BackgroundDependencyLoader] private void load(OsuColour colours) { AccentColour = colours.Gray6; } - protected override DropdownHeader CreateHeader() => new CollectionsHeader(); + protected override CollectionDropdownHeader CreateCollectionHeader() => new CollectionsHeader(); - protected override DropdownMenu CreateMenu() => new CollectionsMenu(); + protected override CollectionDropdownMenu CreateCollectionMenu() => new CollectionsMenu(); - private class CollectionsMenu : OsuDropdownMenu + private class CollectionsMenu : CollectionDropdownMenu { public CollectionsMenu() { @@ -40,7 +44,7 @@ namespace osu.Game.Overlays.Music } } - private class CollectionsHeader : OsuDropdownHeader + private class CollectionsHeader : CollectionDropdownHeader { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs index 278bb55170..66adbeebe8 100644 --- a/osu.Game/Overlays/Music/FilterControl.cs +++ b/osu.Game/Overlays/Music/FilterControl.cs @@ -8,13 +8,15 @@ using osu.Game.Graphics.UserInterface; using osuTK; using System; using osu.Framework.Allocation; -using osu.Framework.Bindables; namespace osu.Game.Overlays.Music { public class FilterControl : Container { + public Action FilterChanged; + public readonly FilterTextBox Search; + private readonly CollectionDropdown collectionDropdown; public FilterControl() { @@ -32,21 +34,27 @@ namespace osu.Game.Overlays.Music RelativeSizeAxes = Axes.X, Height = 40, }, - new CollectionsDropdown - { - RelativeSizeAxes = Axes.X, - Items = new[] { PlaylistCollection.All }, - } + collectionDropdown = new CollectionDropdown { RelativeSizeAxes = Axes.X } }, }, }; - - Search.Current.ValueChanged += current_ValueChanged; } - private void current_ValueChanged(ValueChangedEvent e) => FilterChanged?.Invoke(e.NewValue); + protected override void LoadComplete() + { + base.LoadComplete(); - public Action FilterChanged; + Search.Current.BindValueChanged(_ => updateCriteria()); + collectionDropdown.Current.BindValueChanged(_ => updateCriteria(), true); + } + + private void updateCriteria() => FilterChanged?.Invoke(createCriteria()); + + private FilterCriteria createCriteria() => new FilterCriteria + { + SearchText = Search.Current.Value, + Collection = collectionDropdown.Current.Value?.Collection + }; public class FilterTextBox : SearchTextBox { diff --git a/osu.Game/Overlays/Music/FilterCriteria.cs b/osu.Game/Overlays/Music/FilterCriteria.cs new file mode 100644 index 0000000000..f15edff4d0 --- /dev/null +++ b/osu.Game/Overlays/Music/FilterCriteria.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Game.Collections; + +namespace osu.Game.Overlays.Music +{ + public class FilterCriteria + { + /// + /// The search text. + /// + public string SearchText; + + /// + /// The collection to filter beatmaps from. + /// + [CanBeNull] + public BeatmapCollection Collection; + } +} diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index 621a533dd6..4fe338926f 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -24,7 +24,15 @@ namespace osu.Game.Overlays.Music set => base.Padding = value; } - public void Filter(string searchTerm) => ((SearchContainer>)ListContainer).SearchTerm = searchTerm; + public void Filter(FilterCriteria criteria) + { + var items = (SearchContainer>)ListContainer; + + foreach (var item in items.OfType()) + item.InSelectedCollection = criteria.Collection?.Beatmaps.Any(b => b.BeatmapSet.Equals(item.Model)) ?? true; + + items.SearchTerm = criteria.SearchText; + } public BeatmapSetInfo FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 840fa51b4f..96dff39fae 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -95,23 +95,40 @@ namespace osu.Game.Overlays.Music return true; } + private bool inSelectedCollection = true; + + public bool InSelectedCollection + { + get => inSelectedCollection; + set + { + if (inSelectedCollection == value) + return; + + inSelectedCollection = value; + updateFilter(); + } + } + public IEnumerable FilterTerms { get; } - private bool matching = true; + private bool matchingFilter = true; public bool MatchingFilter { - get => matching; + get => matchingFilter && inSelectedCollection; set { - if (matching == value) return; + if (matchingFilter == value) + return; - matching = value; - - this.FadeTo(matching ? 1 : 0, 200); + matchingFilter = value; + updateFilter(); } } + private void updateFilter() => this.FadeTo(MatchingFilter ? 1 : 0, 200); + public bool FilteringActive { get; set; } } } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index b45d84049f..050e687dfb 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Music { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - FilterChanged = search => list.Filter(search), + FilterChanged = criteria => list.Filter(criteria), Padding = new MarginPadding(10), }, }, @@ -124,10 +124,4 @@ namespace osu.Game.Overlays.Music beatmap.Value.Track.Restart(); } } - - //todo: placeholder - public enum PlaylistCollection - { - All - } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index b9cc054ed3..e42a359d2e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -82,57 +82,49 @@ namespace osu.Game.Rulesets.Edit return; } - InternalChild = new GridContainer + const float toolbar_width = 200; + + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new Container { - new Drawable[] + Name = "Content", + Padding = new MarginPadding { Left = toolbar_width }, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - new FillFlowContainer + // layers below playfield + drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[] { - Name = "Sidebar", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 10 }, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new ToolboxGroup("toolbox") { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } }, - new ToolboxGroup("toggles") - { - ChildrenEnumerable = Toggles.Select(b => new SettingsCheckbox - { - Bindable = b, - LabelText = b?.Description ?? "unknown" - }) - } - } - }, - new Container - { - Name = "Content", - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new Drawable[] - { - // layers below playfield - drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[] - { - LayerBelowRuleset, - new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both } - }), - drawableRulesetWrapper, - // layers above playfield - drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer() - .WithChild(BlueprintContainer = CreateBlueprintContainer(HitObjects)) - } - } - }, + LayerBelowRuleset, + new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both } + }), + drawableRulesetWrapper, + // layers above playfield + drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer() + .WithChild(BlueprintContainer = CreateBlueprintContainer(HitObjects)) + } }, - ColumnDimensions = new[] + new FillFlowContainer { - new Dimension(GridSizeMode.Absolute, 200), - } + Name = "Sidebar", + RelativeSizeAxes = Axes.Y, + Width = toolbar_width, + Padding = new MarginPadding { Right = 10 }, + Spacing = new Vector2(10), + Children = new Drawable[] + { + new ToolboxGroup("toolbox") { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } }, + new ToolboxGroup("toggles") + { + ChildrenEnumerable = Toggles.Select(b => new SettingsCheckbox + { + Bindable = b, + LabelText = b?.Description ?? "unknown" + }) + } + } + }, }; toolboxCollection.Items = CompositionTools diff --git a/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs b/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs deleted file mode 100644 index 9e7f8e7394..0000000000 --- a/osu.Game/Screens/Play/PlayerSettings/CollectionSettings.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Overlays.Music; - -namespace osu.Game.Screens.Play.PlayerSettings -{ - public class CollectionSettings : PlayerSettingsGroup - { - public CollectionSettings() - : base("collections") - { - } - - [BackgroundDependencyLoader] - private void load() - { - Children = new Drawable[] - { - new OsuSpriteText - { - Text = @"Add current song to", - }, - new CollectionsDropdown - { - RelativeSizeAxes = Axes.X, - Items = new[] { PlaylistCollection.All }, - }, - }; - } - } -} diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 079667a457..c82a3742cc 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Game.Collections; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers;