From 9c664e5b052f0d74fe514a6b98e8d312c173a286 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 02:08:42 +0900 Subject: [PATCH 01/20] Reorganise song select methods to allow for more flexibility. --- osu.Game/Screens/Select/SongSelect.cs | 70 +++++++++++++++++---------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a0f20242c2..45485ecebc 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -352,39 +352,68 @@ namespace osu.Game.Screens.Select } } - private void addBeatmapSet(BeatmapSetInfo beatmapSet, Framework.Game game, bool select = false) + private BeatmapGroup prepareBeatmapSet(BeatmapSetInfo beatmapSet) { - beatmapSet = database.GetWithChildren(beatmapSet.ID); - beatmapSet.Beatmaps.ForEach(b => - { - database.GetChildren(b); - if (b.Metadata == null) b.Metadata = beatmapSet.Metadata; - }); + database.GetChildren(beatmapSet); + beatmapSet.Beatmaps.ForEach(b => { if (b.Metadata == null) b.Metadata = beatmapSet.Metadata; }); - var group = new BeatmapGroup(beatmapSet, database) + return new BeatmapGroup(beatmapSet, database) { SelectionChanged = selectionChanged, StartRequested = b => raiseSelect() }; + } + + private void addBeatmapSet(BeatmapSetInfo beatmapSet, Framework.Game game, bool select = false) + { + var group = prepareBeatmapSet(beatmapSet); //for the time being, let's completely load the difficulty panels in the background. //this likely won't scale so well, but allows us to completely async the loading flow. Task.WhenAll(group.BeatmapPanels.Select(panel => panel.LoadAsync(game))).ContinueWith(task => Schedule(delegate { - beatmapGroups.Add(group); - - group.State = BeatmapGroupState.Collapsed; - carousel.AddGroup(group); - - filterChanged(false, false); + addGroup(group); if (Beatmap == null || select) - carousel.SelectBeatmap(beatmapSet.Beatmaps.First()); + selectBeatmap(beatmapSet); else - carousel.SelectBeatmap(Beatmap.BeatmapInfo); + selectBeatmap(); })); } + private void addGroup(BeatmapGroup group) + { + beatmapGroups.Add(group); + + group.State = BeatmapGroupState.Collapsed; + carousel.AddGroup(group); + + filterChanged(false, false); + } + + private void selectBeatmap(BeatmapSetInfo beatmapSet = null) + { + carousel.SelectBeatmap(beatmapSet != null ? beatmapSet.Beatmaps.First() : Beatmap.BeatmapInfo); + } + + private void addBeatmapSets(Framework.Game game, CancellationToken token) + { + List groups = new List(); + + foreach (var beatmapSet in database.Query().Where(b => !b.DeletePending)) + { + if (token.IsCancellationRequested) return; + + groups.Add(prepareBeatmapSet(beatmapSet)); + } + + Schedule(() => + { + groups.ForEach(addGroup); + selectBeatmap(Beatmap?.BeatmapSetInfo ?? groups.First().BeatmapSet); + }); + } + private void removeBeatmapSet(BeatmapSetInfo beatmapSet) { var group = beatmapGroups.Find(b => b.BeatmapSet.ID == beatmapSet.ID); @@ -400,15 +429,6 @@ namespace osu.Game.Screens.Select Beatmap = null; } - private void addBeatmapSets(Framework.Game game, CancellationToken token) - { - foreach (var beatmapSet in database.Query().Where(b => !b.DeletePending)) - { - if (token.IsCancellationRequested) return; - addBeatmapSet(beatmapSet, game); - } - } - private void promptDelete() { if (Beatmap != null) From cd98af29c409b190c4bd294f026c219c5b0f7a89 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 11:53:13 +0900 Subject: [PATCH 02/20] Only calculate difficulties on import for now. --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 2 -- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 +- osu.Game/Database/BeatmapDatabase.cs | 2 ++ osu.Game/Database/BeatmapInfo.cs | 11 +---------- osu.Game/Database/BeatmapSetInfo.cs | 2 +- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index 2cccbc322a..a2824f01e3 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -63,8 +63,6 @@ namespace osu.Game.Beatmaps.Drawables { BeatmapSet = beatmapSet; WorkingBeatmap beatmap = database.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault()); - foreach (var b in BeatmapSet.Beatmaps) - b.StarDifficulty = (float)(database.GetWorkingBeatmap(b).Beatmap?.CalculateStarDifficulty() ?? -1f); Header = new BeatmapSetHeader(beatmap) { diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index aa5891c37e..191cb405d0 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -138,7 +138,7 @@ namespace osu.Game.Beatmaps.Drawables }, starCounter = new StarCounter { - Count = beatmap.StarDifficulty, + Count = (float)beatmap.StarDifficulty, Scale = new Vector2(0.8f), } } diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs index b3d48c152f..ef1444ffa4 100644 --- a/osu.Game/Database/BeatmapDatabase.cs +++ b/osu.Game/Database/BeatmapDatabase.cs @@ -236,6 +236,8 @@ namespace osu.Game.Database // TODO: Diff beatmap metadata with set metadata and leave it here if necessary beatmap.BeatmapInfo.Metadata = null; + beatmap.BeatmapInfo.StarDifficulty = beatmap.CalculateStarDifficulty(); + beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); } beatmapSet.StoryboardFile = archive.StoryboardFilename; diff --git a/osu.Game/Database/BeatmapInfo.cs b/osu.Game/Database/BeatmapInfo.cs index 5f9c0baee8..cda9cba70c 100644 --- a/osu.Game/Database/BeatmapInfo.cs +++ b/osu.Game/Database/BeatmapInfo.cs @@ -75,16 +75,7 @@ namespace osu.Game.Database // Metadata public string Version { get; set; } - private float starDifficulty = -1; - public float StarDifficulty - { - get - { - return starDifficulty < 0 ? (Difficulty?.OverallDifficulty ?? 5) : starDifficulty; - } - - set { starDifficulty = value; } - } + public double StarDifficulty { get; set; } public bool Equals(BeatmapInfo other) { diff --git a/osu.Game/Database/BeatmapSetInfo.cs b/osu.Game/Database/BeatmapSetInfo.cs index 12247c3997..0ef0ba4c63 100644 --- a/osu.Game/Database/BeatmapSetInfo.cs +++ b/osu.Game/Database/BeatmapSetInfo.cs @@ -24,7 +24,7 @@ namespace osu.Game.Database [OneToMany(CascadeOperations = CascadeOperation.All)] public List Beatmaps { get; set; } - public float MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty); + public double MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty); public bool DeletePending { get; set; } From 2abcdbf4dfb7a5bc07dc02cacfdc5ab1bedd6201 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 14:56:12 +0900 Subject: [PATCH 03/20] Fix potentially incorrect states being applied to panels on first display. --- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 ++ osu.Game/Beatmaps/Drawables/Panel.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index 191cb405d0..f04d35efc3 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -59,6 +59,8 @@ namespace osu.Game.Beatmaps.Drawables protected override void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden) { + if (!IsLoaded) return; + base.ApplyState(last); if (last == PanelSelectedState.Hidden && State != last) diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index a15d0c22f0..fba586bc05 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.cs @@ -51,6 +51,8 @@ namespace osu.Game.Beatmaps.Drawables protected virtual void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden) { + if (!IsLoaded) return; + switch (state) { case PanelSelectedState.Hidden: From ba73968303b3e6ac29dff7ff69219e408388041d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 18:28:21 +0900 Subject: [PATCH 04/20] Load whole panel background in async. --- .../Beatmaps/Drawables/BeatmapSetHeader.cs | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index c1ac93f70c..cb6fa02553 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -32,10 +32,6 @@ namespace osu.Game.Beatmaps.Drawables Children = new Drawable[] { - new PanelBackground(beatmap) - { - RelativeSizeAxes = Axes.Both, - }, new FillFlowContainer { Direction = FillDirection.Vertical, @@ -74,13 +70,23 @@ namespace osu.Game.Beatmaps.Drawables } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load(OsuConfigManager config, OsuGameBase game) { this.config = config; preferUnicode = config.GetBindable(OsuConfig.ShowUnicode); preferUnicode.ValueChanged += preferUnicode_changed; preferUnicode_changed(preferUnicode, null); + + new PanelBackground(beatmap) + { + RelativeSizeAxes = Axes.Both, + Depth = 1, + }.LoadAsync(game, b => + { + Add(b); + b.FadeInFromZero(200); + }); } private void preferUnicode_changed(object sender, EventArgs e) @@ -98,16 +104,18 @@ namespace osu.Game.Beatmaps.Drawables private class PanelBackground : BufferedContainer { - private readonly WorkingBeatmap working; - public PanelBackground(WorkingBeatmap working) { - this.working = working; - CacheDrawnFrameBuffer = true; - Children = new[] + Children = new Drawable[] { + new BeatmapBackgroundSprite(working) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + }, new FillFlowContainer { Depth = -1, @@ -151,21 +159,6 @@ namespace osu.Game.Beatmaps.Drawables }, }; } - - [BackgroundDependencyLoader] - private void load(OsuGameBase game) - { - new BeatmapBackgroundSprite(working) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - }.LoadAsync(game, bg => - { - Add(bg); - ForceRedraw(); - }); - } } public void AddDifficultyIcons(IEnumerable panels) From 34017596652efb04f7b7e6c658d47d43cd55b802 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 18:57:24 +0900 Subject: [PATCH 05/20] Don't batch imports for now. --- osu.Game/Database/BeatmapDatabase.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs index ef1444ffa4..3f865d65f1 100644 --- a/osu.Game/Database/BeatmapDatabase.cs +++ b/osu.Game/Database/BeatmapDatabase.cs @@ -123,16 +123,15 @@ namespace osu.Game.Database /// Multiple locations on disk public void Import(IEnumerable paths) { - Stack sets = new Stack(); - foreach (string p in paths) + { try { BeatmapSetInfo set = getBeatmapSet(p); //If we have an ID then we already exist in the database. if (set.ID == 0) - sets.Push(set); + Import(new[] { set }); // We may or may not want to delete the file depending on where it is stored. // e.g. reconstructing/repairing database with beatmaps from default storage. @@ -152,9 +151,7 @@ namespace osu.Game.Database e = e.InnerException ?? e; Logger.Error(e, @"Could not import beatmap set"); } - - // Batch commit with multiple sets to database - Import(sets); + } } /// From dc28f8c79ea7d0636a00b593140211cd196c9381 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 19:12:15 +0900 Subject: [PATCH 06/20] Remove all external access to BeatmapGroup. --- osu.Game/Screens/Select/CarouselContainer.cs | 431 ++++++++++++------- osu.Game/Screens/Select/SongSelect.cs | 100 +---- 2 files changed, 287 insertions(+), 244 deletions(-) diff --git a/osu.Game/Screens/Select/CarouselContainer.cs b/osu.Game/Screens/Select/CarouselContainer.cs index 092e4461e0..6277abd3cb 100644 --- a/osu.Game/Screens/Select/CarouselContainer.cs +++ b/osu.Game/Screens/Select/CarouselContainer.cs @@ -15,47 +15,227 @@ using OpenTK.Input; using System.Collections; using osu.Framework.MathUtils; using System.Diagnostics; +using System.Threading.Tasks; +using osu.Framework.Allocation; using osu.Game.Screens.Select.Filter; namespace osu.Game.Screens.Select { internal class CarouselContainer : ScrollContainer, IEnumerable { - private Container scrollableContent; - private List groups = new List(); - private List panels = new List(); + public BeatmapInfo SelectedBeatmap => selectedPanel?.Beatmap; - public BeatmapGroup SelectedGroup { get; private set; } - public BeatmapPanel SelectedPanel { get; private set; } + public Action BeatmapsChanged; + + public IEnumerable Beatmaps + { + get + { + return groups.Select(g => g.BeatmapSet); + } + + set + { + scrollableContent.Clear(false); + panels.Clear(); + groups.Clear(); + + IEnumerable newGroups = null; + + Task.Run(() => + { + newGroups = value.Select(createGroup).ToList(); + }).ContinueWith(t => + { + Schedule(() => + { + foreach (var g in newGroups) + addGroup(g); + computeYPositions(); + + BeatmapsChanged?.Invoke(); + }); + }); + } + } private List yPositions = new List(); + /// + /// Required for now unfortunately. + /// + private BeatmapDatabase database; + + private Container scrollableContent; + + private List groups = new List(); + + private List panels = new List(); + + private BeatmapGroup selectedGroup; + + private BeatmapPanel selectedPanel; + public CarouselContainer() { - DistanceDecayJump = 0.01; - Add(scrollableContent = new Container { RelativeSizeAxes = Axes.X, }); } - public void AddGroup(BeatmapGroup group) + public void AddBeatmap(BeatmapSetInfo beatmapSet) { - groups.Add(group); + var group = createGroup(beatmapSet); - panels.Add(group.Header); - group.Header.UpdateClock(Clock); - foreach (BeatmapPanel panel in group.BeatmapPanels) + //for the time being, let's completely load the difficulty panels in the background. + //this likely won't scale so well, but allows us to completely async the loading flow. + Schedule(delegate { - panels.Add(panel); - panel.UpdateClock(Clock); + addGroup(group); + computeYPositions(); + if (selectedGroup == null) + selectGroup(group); + }); + } + + public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true) + { + if (beatmap == null) + { + SelectNext(); + return; } + foreach (BeatmapGroup group in groups) + { + var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + if (panel != null) + { + selectGroup(group, panel, animated); + return; + } + } + } + + public void RemoveBeatmap(BeatmapSetInfo info) => removeGroup(groups.Find(b => b.BeatmapSet.ID == info.ID)); + + public Action SelectionChanged; + + public Action StartRequested; + + public void SelectNext(int direction = 1, bool skipDifficulties = true) + { + if (groups.Count == 0) + { + selectedGroup = null; + selectedPanel = null; + return; + } + + if (!skipDifficulties && selectedGroup != null) + { + int i = selectedGroup.BeatmapPanels.IndexOf(selectedPanel) + direction; + + if (i >= 0 && i < selectedGroup.BeatmapPanels.Count) + { + //changing difficulty panel, not set. + selectGroup(selectedGroup, selectedGroup.BeatmapPanels[i]); + return; + } + } + + int startIndex = groups.IndexOf(selectedGroup); + int index = startIndex; + + do + { + index = (index + direction + groups.Count) % groups.Count; + if (groups[index].State != BeatmapGroupState.Hidden) + { + SelectBeatmap(groups[index].BeatmapPanels.First().Beatmap); + return; + } + } while (index != startIndex); + } + + public void SelectRandom() + { + List visibleGroups = groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden).ToList(); + if (visibleGroups.Count < 1) + return; + BeatmapGroup group = visibleGroups[RNG.Next(visibleGroups.Count)]; + BeatmapPanel panel = group?.BeatmapPanels.First(); + + if (panel == null) + return; + + selectGroup(group, panel); + } + + public void Sort(SortMode mode) + { + List sortedGroups = new List(groups); + switch (mode) + { + case SortMode.Artist: + sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase)); + break; + case SortMode.Title: + sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Title, y.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase)); + break; + case SortMode.Author: + sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Author, y.BeatmapSet.Metadata.Author, StringComparison.InvariantCultureIgnoreCase)); + break; + case SortMode.Difficulty: + sortedGroups.Sort((x, y) => x.BeatmapSet.MaxStarDifficulty.CompareTo(y.BeatmapSet.MaxStarDifficulty)); + break; + default: + Sort(SortMode.Artist); // Temporary + break; + } + + scrollableContent.Clear(false); + panels.Clear(); + groups.Clear(); + + foreach (var g in sortedGroups) + addGroup(g); + computeYPositions(); } - public void RemoveGroup(BeatmapGroup group) + public IEnumerator GetEnumerator() => groups.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet) + { + database.GetChildren(beatmapSet); + beatmapSet.Beatmaps.ForEach(b => { if (b.Metadata == null) b.Metadata = beatmapSet.Metadata; }); + + return new BeatmapGroup(beatmapSet, database) + { + SelectionChanged = SelectionChanged, + StartRequested = b => StartRequested?.Invoke(), + State = BeatmapGroupState.Collapsed + }; + } + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(BeatmapDatabase database) + { + this.database = database; + } + + private void addGroup(BeatmapGroup group) + { + groups.Add(group); + panels.Add(group.Header); + panels.AddRange(group.BeatmapPanels); + } + + private void removeGroup(BeatmapGroup group) { groups.Remove(group); panels.Remove(group.Header); @@ -65,18 +245,12 @@ namespace osu.Game.Screens.Select scrollableContent.Remove(group.Header); scrollableContent.Remove(group.BeatmapPanels); + if (selectedGroup == group) + SelectNext(); + computeYPositions(); } - private void movePanel(Panel panel, bool advance, bool animated, ref float currentY) - { - yPositions.Add(currentY); - panel.MoveToY(currentY, animated ? 750 : 0, EasingTypes.OutExpo); - - if (advance) - currentY += panel.DrawHeight + 5; - } - /// /// Computes the target Y positions for every panel in the carousel. /// @@ -99,7 +273,7 @@ namespace osu.Game.Screens.Select foreach (BeatmapPanel panel in group.BeatmapPanels) { - if (panel == SelectedPanel) + if (panel == selectedPanel) selectedY = currentY + panel.DrawHeight / 2 - DrawHeight / 2; panel.MoveToX(-50, 500, EasingTypes.OutExpo); @@ -129,105 +303,62 @@ namespace osu.Game.Screens.Select return selectedY; } - public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true) + private void movePanel(Panel panel, bool advance, bool animated, ref float currentY) { - foreach (BeatmapGroup group in groups) - { - var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); - if (panel != null) - { - selectGroup(group, panel, animated); - return; - } - } + yPositions.Add(currentY); + panel.MoveToY(currentY, animated ? 750 : 0, EasingTypes.OutExpo); + + if (advance) + currentY += panel.DrawHeight + 5; } - private void selectGroup(BeatmapGroup group, BeatmapPanel panel, bool animated = true) + private void selectGroup(BeatmapGroup group, BeatmapPanel panel = null, bool animated = true) { + if (panel == null) + panel = group.BeatmapPanels.First(); + Trace.Assert(group.BeatmapPanels.Contains(panel), @"Selected panel must be in provided group"); - if (SelectedGroup != null && SelectedGroup != group && SelectedGroup.State != BeatmapGroupState.Hidden) - SelectedGroup.State = BeatmapGroupState.Collapsed; + if (selectedGroup != null && selectedGroup != group && selectedGroup.State != BeatmapGroupState.Hidden) + selectedGroup.State = BeatmapGroupState.Collapsed; group.State = BeatmapGroupState.Expanded; - SelectedGroup = group; + selectedGroup = group; panel.State = PanelSelectedState.Selected; - SelectedPanel = panel; + selectedPanel = panel; float selectedY = computeYPositions(animated); ScrollTo(selectedY, animated); } - public void Sort(SortMode mode) + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { - List sortedGroups = new List(groups); - switch (mode) + int direction = 0; + bool skipDifficulties = false; + + switch (args.Key) { - case SortMode.Artist: - sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase)); + case Key.Up: + direction = -1; break; - case SortMode.Title: - sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Title, y.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase)); + case Key.Down: + direction = 1; break; - case SortMode.Author: - sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Author, y.BeatmapSet.Metadata.Author, StringComparison.InvariantCultureIgnoreCase)); + case Key.Left: + direction = -1; + skipDifficulties = true; break; - case SortMode.Difficulty: - sortedGroups.Sort((x, y) => x.BeatmapSet.MaxStarDifficulty.CompareTo(y.BeatmapSet.MaxStarDifficulty)); - break; - default: - Sort(SortMode.Artist); // Temporary + case Key.Right: + direction = 1; + skipDifficulties = true; break; } - scrollableContent.Clear(false); - panels.Clear(); - groups.Clear(); + if (direction == 0) + return base.OnKeyDown(state, args); - foreach (BeatmapGroup group in sortedGroups) - AddGroup(group); - } - - /// - /// Computes the x-offset of currently visible panels. Makes the carousel appear round. - /// - /// - /// Vertical distance from the center of the carousel container - /// ranging from -1 to 1. - /// - /// Half the height of the carousel container. - private static float offsetX(float dist, float halfHeight) - { - // The radius of the circle the carousel moves on. - const float circle_radius = 3; - double discriminant = Math.Max(0, circle_radius * circle_radius - dist * dist); - float x = (circle_radius - (float)Math.Sqrt(discriminant)) * halfHeight; - - return 125 + x; - } - - /// - /// Update a panel's x position and multiplicative alpha based on its y position and - /// the current scroll position. - /// - /// The panel to be updated. - /// Half the draw height of the carousel container. - private void updatePanel(Panel p, float halfHeight) - { - var height = p.IsPresent ? p.DrawHeight : 0; - - float panelDrawY = p.Position.Y - Current + height / 2; - float dist = Math.Abs(1f - panelDrawY / halfHeight); - - // Setting the origin position serves as an additive position on top of potential - // local transformation we may want to apply (e.g. when a panel gets selected, we - // may want to smoothly transform it leftwards.) - p.OriginPosition = new Vector2(-offsetX(dist, halfHeight), 0); - - // We are applying a multiplicative alpha (which is internally done by nesting an - // additional container and setting that container's alpha) such that we can - // layer transformations on top, with a similar reasoning to the previous comment. - p.SetMultiplicativeAlpha(MathHelper.Clamp(1.75f - 1.5f * dist, 0, 1)); + SelectNext(direction, skipDifficulties); + return true; } protected override void Update() @@ -276,80 +407,46 @@ namespace osu.Game.Screens.Select updatePanel(p, halfHeight); } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + /// + /// Computes the x-offset of currently visible panels. Makes the carousel appear round. + /// + /// + /// Vertical distance from the center of the carousel container + /// ranging from -1 to 1. + /// + /// Half the height of the carousel container. + private static float offsetX(float dist, float halfHeight) { - int direction = 0; - bool skipDifficulties = false; + // The radius of the circle the carousel moves on. + const float circle_radius = 3; + double discriminant = Math.Max(0, circle_radius * circle_radius - dist * dist); + float x = (circle_radius - (float)Math.Sqrt(discriminant)) * halfHeight; - switch (args.Key) - { - case Key.Up: - direction = -1; - break; - case Key.Down: - direction = 1; - break; - case Key.Left: - direction = -1; - skipDifficulties = true; - break; - case Key.Right: - direction = 1; - skipDifficulties = true; - break; - } - - if (direction == 0) - return base.OnKeyDown(state, args); - - SelectNext(direction, skipDifficulties); - return true; + return 125 + x; } - public void SelectNext(int direction = 1, bool skipDifficulties = true) + /// + /// Update a panel's x position and multiplicative alpha based on its y position and + /// the current scroll position. + /// + /// The panel to be updated. + /// Half the draw height of the carousel container. + private void updatePanel(Panel p, float halfHeight) { - if (!skipDifficulties && SelectedGroup != null) - { - int i = SelectedGroup.BeatmapPanels.IndexOf(SelectedPanel) + direction; + var height = p.IsPresent ? p.DrawHeight : 0; - if (i >= 0 && i < SelectedGroup.BeatmapPanels.Count) - { - //changing difficulty panel, not set. - selectGroup(SelectedGroup, SelectedGroup.BeatmapPanels[i]); - return; - } - } + float panelDrawY = p.Position.Y - Current + height / 2; + float dist = Math.Abs(1f - panelDrawY / halfHeight); - int startIndex = groups.IndexOf(SelectedGroup); - int index = startIndex; + // Setting the origin position serves as an additive position on top of potential + // local transformation we may want to apply (e.g. when a panel gets selected, we + // may want to smoothly transform it leftwards.) + p.OriginPosition = new Vector2(-offsetX(dist, halfHeight), 0); - do - { - index = (index + direction + groups.Count) % groups.Count; - if (groups[index].State != BeatmapGroupState.Hidden) - { - SelectBeatmap(groups[index].BeatmapPanels.First().Beatmap); - return; - } - } while (index != startIndex); + // We are applying a multiplicative alpha (which is internally done by nesting an + // additional container and setting that container's alpha) such that we can + // layer transformations on top, with a similar reasoning to the previous comment. + p.SetMultiplicativeAlpha(MathHelper.Clamp(1.75f - 1.5f * dist, 0, 1)); } - - public void SelectRandom() - { - List visibleGroups = groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden).ToList(); - if (visibleGroups.Count < 1) - return; - BeatmapGroup group = visibleGroups[RNG.Next(visibleGroups.Count)]; - BeatmapPanel panel = group?.BeatmapPanels.First(); - - if (panel == null) - return; - - selectGroup(group, panel); - } - - public IEnumerator GetEnumerator() => groups.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 45485ecebc..fec1dc89c9 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -2,10 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using OpenTK; using OpenTK.Input; using osu.Framework.Allocation; @@ -51,8 +49,6 @@ namespace osu.Game.Screens.Select private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; - private List beatmapGroups; - protected virtual bool ShowFooter => true; /// @@ -72,7 +68,6 @@ namespace osu.Game.Screens.Select const float carousel_width = 640; const float filter_height = 100; - beatmapGroups = new List(); Add(new ParallaxContainer { Padding = new MarginPadding { Top = filter_height }, @@ -93,6 +88,8 @@ namespace osu.Game.Screens.Select Size = new Vector2(carousel_width, 1), Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + SelectionChanged = selectionChanged, + StartRequested = raiseSelect }); Add(FilterControl = new FilterControl { @@ -132,8 +129,7 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapDatabase beatmaps, AudioManager audio, DialogOverlay dialog, Framework.Game game, - OsuGame osu, OsuColour colours) + private void load(BeatmapDatabase beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours) { if (Footer != null) { @@ -161,7 +157,16 @@ namespace osu.Game.Screens.Select initialAddSetsTask = new CancellationTokenSource(); - Task.Factory.StartNew(() => addBeatmapSets(game, initialAddSetsTask.Token), initialAddSetsTask.Token); + carousel.BeatmapsChanged = beatmapsLoaded; + carousel.Beatmaps = database.Query().Where(b => !b.DeletePending); + } + + private void beatmapsLoaded() + { + if (Beatmap != null) + carousel.SelectBeatmap(Beatmap.BeatmapInfo, false); + else + carousel.SelectNext(); } private void raiseSelect() @@ -173,18 +178,24 @@ namespace osu.Game.Screens.Select } public void SelectRandom() => carousel.SelectRandom(); + protected abstract void OnSelected(); private ScheduledDelegate filterTask; private void filterChanged(bool debounce = true, bool eagerSelection = true) { + if (!carousel.IsLoaded) return; + + if (Beatmap == null) return; + filterTask?.Cancel(); filterTask = Scheduler.AddDelayed(() => { filterTask = null; var search = FilterControl.Search; BeatmapGroup newSelection = null; + carousel.Sort(FilterControl.Sort); foreach (var beatmapGroup in carousel) { @@ -227,7 +238,7 @@ namespace osu.Game.Screens.Select }, debounce ? 250 : 0); } - private void onBeatmapSetAdded(BeatmapSetInfo s) => Schedule(() => addBeatmapSet(s, Game, true)); + private void onBeatmapSetAdded(BeatmapSetInfo s) => carousel.AddBeatmap(s); private void onBeatmapSetRemoved(BeatmapSetInfo s) => Schedule(() => removeBeatmapSet(s)); @@ -352,80 +363,15 @@ namespace osu.Game.Screens.Select } } - private BeatmapGroup prepareBeatmapSet(BeatmapSetInfo beatmapSet) - { - database.GetChildren(beatmapSet); - beatmapSet.Beatmaps.ForEach(b => { if (b.Metadata == null) b.Metadata = beatmapSet.Metadata; }); - - return new BeatmapGroup(beatmapSet, database) - { - SelectionChanged = selectionChanged, - StartRequested = b => raiseSelect() - }; - } - - private void addBeatmapSet(BeatmapSetInfo beatmapSet, Framework.Game game, bool select = false) - { - var group = prepareBeatmapSet(beatmapSet); - - //for the time being, let's completely load the difficulty panels in the background. - //this likely won't scale so well, but allows us to completely async the loading flow. - Task.WhenAll(group.BeatmapPanels.Select(panel => panel.LoadAsync(game))).ContinueWith(task => Schedule(delegate - { - addGroup(group); - - if (Beatmap == null || select) - selectBeatmap(beatmapSet); - else - selectBeatmap(); - })); - } - - private void addGroup(BeatmapGroup group) - { - beatmapGroups.Add(group); - - group.State = BeatmapGroupState.Collapsed; - carousel.AddGroup(group); - - filterChanged(false, false); - } - private void selectBeatmap(BeatmapSetInfo beatmapSet = null) { - carousel.SelectBeatmap(beatmapSet != null ? beatmapSet.Beatmaps.First() : Beatmap.BeatmapInfo); - } - - private void addBeatmapSets(Framework.Game game, CancellationToken token) - { - List groups = new List(); - - foreach (var beatmapSet in database.Query().Where(b => !b.DeletePending)) - { - if (token.IsCancellationRequested) return; - - groups.Add(prepareBeatmapSet(beatmapSet)); - } - - Schedule(() => - { - groups.ForEach(addGroup); - selectBeatmap(Beatmap?.BeatmapSetInfo ?? groups.First().BeatmapSet); - }); + carousel.SelectBeatmap(beatmapSet != null ? beatmapSet.Beatmaps.First() : Beatmap?.BeatmapInfo); } private void removeBeatmapSet(BeatmapSetInfo beatmapSet) { - var group = beatmapGroups.Find(b => b.BeatmapSet.ID == beatmapSet.ID); - if (group == null) return; - - if (carousel.SelectedGroup == group) - carousel.SelectNext(); - - beatmapGroups.Remove(group); - carousel.RemoveGroup(group); - - if (beatmapGroups.Count == 0) + carousel.RemoveBeatmap(beatmapSet); + if (carousel.SelectedBeatmap == null) Beatmap = null; } From 4b97304603b235927aa568e53489fbb845ea922b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 19:12:54 +0900 Subject: [PATCH 07/20] CarouselContainer -> BeatmapCarousel. --- .../Select/{CarouselContainer.cs => BeatmapCarousel.cs} | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 4 ++-- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename osu.Game/Screens/Select/{CarouselContainer.cs => BeatmapCarousel.cs} (96%) diff --git a/osu.Game/Screens/Select/CarouselContainer.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs similarity index 96% rename from osu.Game/Screens/Select/CarouselContainer.cs rename to osu.Game/Screens/Select/BeatmapCarousel.cs index 6277abd3cb..885ca8bfbe 100644 --- a/osu.Game/Screens/Select/CarouselContainer.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -21,7 +21,7 @@ using osu.Game.Screens.Select.Filter; namespace osu.Game.Screens.Select { - internal class CarouselContainer : ScrollContainer, IEnumerable + internal class BeatmapCarousel : ScrollContainer, IEnumerable { public BeatmapInfo SelectedBeatmap => selectedPanel?.Beatmap; @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Select private BeatmapPanel selectedPanel; - public CarouselContainer() + public BeatmapCarousel() { Add(scrollableContent = new Container { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index fec1dc89c9..58a633b682 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Select private BeatmapDatabase database; protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - private CarouselContainer carousel; + private BeatmapCarousel carousel; private TrackManager trackManager; private DialogOverlay dialogOverlay; @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Select } } }); - Add(carousel = new CarouselContainer + Add(carousel = new BeatmapCarousel { RelativeSizeAxes = Axes.Y, Size = new Vector2(carousel_width, 1), diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 80d5c906e0..1864260e2c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -196,7 +196,7 @@ - + From 907236e475a6ee341e0993de94176413fd538340 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 19:54:51 +0900 Subject: [PATCH 08/20] Move filtering to BeatmapCarousel (but actual logic is now in FilterCriteria. --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 2 +- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 +- .../Beatmaps/Drawables/BeatmapSetHeader.cs | 2 +- osu.Game/Beatmaps/Drawables/Panel.cs | 4 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 63 ++++++++++-------- osu.Game/Screens/Select/FilterControl.cs | 35 ++++++---- osu.Game/Screens/Select/FilterCriteria.cs | 62 ++++++++++++++++++ osu.Game/Screens/Select/SongSelect.cs | 64 ++----------------- osu.Game/osu.Game.csproj | 1 + 9 files changed, 131 insertions(+), 104 deletions(-) create mode 100644 osu.Game/Screens/Select/FilterCriteria.cs diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index a2824f01e3..ac0ab9966f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -10,7 +10,7 @@ using osu.Game.Database; namespace osu.Game.Beatmaps.Drawables { - internal class BeatmapGroup : IStateful + public class BeatmapGroup : IStateful { public BeatmapPanel SelectedPanel; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index f04d35efc3..67ebb2fcb9 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -18,7 +18,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Beatmaps.Drawables { - internal class BeatmapPanel : Panel + public class BeatmapPanel : Panel { public BeatmapInfo Beatmap; private Sprite background; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index cb6fa02553..3dc5fdedc9 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -17,7 +17,7 @@ using OpenTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - internal class BeatmapSetHeader : Panel + public class BeatmapSetHeader : Panel { public Action GainedSelection; private SpriteText title, artist; diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index fba586bc05..c51ae8680e 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.cs @@ -12,7 +12,7 @@ using osu.Framework.Extensions.Color4Extensions; namespace osu.Game.Beatmaps.Drawables { - internal class Panel : Container, IStateful + public class Panel : Container, IStateful { public const float MAX_HEIGHT = 80; @@ -117,7 +117,7 @@ namespace osu.Game.Beatmaps.Drawables } } - internal enum PanelSelectedState + public enum PanelSelectedState { Hidden, NotSelected, diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 885ca8bfbe..20ebfb3837 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -17,7 +17,7 @@ using osu.Framework.MathUtils; using System.Diagnostics; using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Game.Screens.Select.Filter; +using osu.Framework.Threading; namespace osu.Game.Screens.Select { @@ -40,19 +40,20 @@ namespace osu.Game.Screens.Select panels.Clear(); groups.Clear(); - IEnumerable newGroups = null; + List newGroups = null; Task.Run(() => { newGroups = value.Select(createGroup).ToList(); + criteria.Filter(newGroups); }).ContinueWith(t => { Schedule(() => { foreach (var g in newGroups) addGroup(g); - computeYPositions(); + computeYPositions(); BeatmapsChanged?.Invoke(); }); }); @@ -173,36 +174,42 @@ namespace osu.Game.Screens.Select selectGroup(group, panel); } - public void Sort(SortMode mode) + private FilterCriteria criteria = new FilterCriteria(); + + private ScheduledDelegate filterTask; + + public void Filter(FilterCriteria newCriteria = null, bool debounce = true) { - List sortedGroups = new List(groups); - switch (mode) + if (!IsLoaded) return; + + criteria = newCriteria ?? criteria ?? new FilterCriteria(); + + Action perform = delegate { - case SortMode.Artist: - sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase)); - break; - case SortMode.Title: - sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Title, y.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase)); - break; - case SortMode.Author: - sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Author, y.BeatmapSet.Metadata.Author, StringComparison.InvariantCultureIgnoreCase)); - break; - case SortMode.Difficulty: - sortedGroups.Sort((x, y) => x.BeatmapSet.MaxStarDifficulty.CompareTo(y.BeatmapSet.MaxStarDifficulty)); - break; - default: - Sort(SortMode.Artist); // Temporary - break; - } + filterTask = null; - scrollableContent.Clear(false); - panels.Clear(); - groups.Clear(); + criteria.Filter(groups); - foreach (var g in sortedGroups) - addGroup(g); + var filtered = new List(groups); - computeYPositions(); + scrollableContent.Clear(false); + panels.Clear(); + groups.Clear(); + + foreach (var g in filtered) + addGroup(g); + + computeYPositions(); + + if (selectedGroup.State == BeatmapGroupState.Hidden) + SelectNext(); + }; + + filterTask?.Cancel(); + if (debounce) + filterTask = Scheduler.AddDelayed(perform, 250); + else + perform(); } public IEnumerator GetEnumerator() => groups.GetEnumerator(); diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 2a25928dc7..9658509981 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -5,6 +5,7 @@ using System; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; @@ -15,14 +16,13 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Select.Filter; using Container = osu.Framework.Graphics.Containers.Container; using osu.Framework.Input; +using osu.Game.Modes; namespace osu.Game.Screens.Select { public class FilterControl : Container { - public Action FilterChanged; - - public string Search => searchTextBox.Text; + public Action FilterChanged; private OsuTabControl sortTabs; @@ -30,16 +30,16 @@ namespace osu.Game.Screens.Select private SortMode sort = SortMode.Title; public SortMode Sort - { - get { return sort; } + { + get { return sort; } set { if (sort != value) { sort = value; - FilterChanged?.Invoke(); + FilterChanged?.Invoke(Criteria); } - } + } } private GroupMode group = GroupMode.All; @@ -51,11 +51,19 @@ namespace osu.Game.Screens.Select if (group != value) { group = value; - FilterChanged?.Invoke(); + FilterChanged?.Invoke(Criteria); } } } + public FilterCriteria Criteria => new FilterCriteria + { + Group = group, + Sort = sort, + SearchText = searchTextBox.Text, + Mode = playMode + }; + public Action Exit; private SearchTextBox searchTextBox; @@ -88,7 +96,7 @@ namespace osu.Game.Screens.Select OnChange = (sender, newText) => { if (newText) - FilterChanged?.Invoke(); + FilterChanged?.Invoke(Criteria); }, Exit = () => Exit?.Invoke(), }, @@ -152,16 +160,21 @@ namespace osu.Game.Screens.Select searchTextBox.HoldFocus = false; searchTextBox.TriggerFocusLost(); } - + public void Activate() { searchTextBox.HoldFocus = true; } + private readonly Bindable playMode = new Bindable(); + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, OsuGame osu) { sortTabs.AccentColour = colours.GreenLight; + + if (osu != null) + playMode.BindTo(osu.PlayMode); } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs new file mode 100644 index 0000000000..f5afafa709 --- /dev/null +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Modes; +using osu.Game.Screens.Select.Filter; + +namespace osu.Game.Screens.Select +{ + public class FilterCriteria + { + public GroupMode Group; + public SortMode Sort; + public string SearchText; + public PlayMode Mode; + + public void Filter(List groups) + { + foreach (var g in groups) + { + var set = g.BeatmapSet; + + bool hasCurrentMode = set.Beatmaps.Any(bm => bm.Mode == Mode); + + bool match = hasCurrentMode; + + match &= string.IsNullOrEmpty(SearchText) + || (set.Metadata.Artist ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1 + || (set.Metadata.ArtistUnicode ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1 + || (set.Metadata.Title ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1 + || (set.Metadata.TitleUnicode ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1; + + switch (g.State) + { + case BeatmapGroupState.Hidden: + if (match) g.State = BeatmapGroupState.Collapsed; + break; + default: + if (!match) g.State = BeatmapGroupState.Hidden; + break; + } + } + + switch (Sort) + { + default: + case SortMode.Artist: + groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase)); + break; + case SortMode.Title: + groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Title, y.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase)); + break; + case SortMode.Author: + groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Author, y.BeatmapSet.Metadata.Author, StringComparison.InvariantCultureIgnoreCase)); + break; + case SortMode.Difficulty: + groups.Sort((x, y) => x.BeatmapSet.MaxStarDifficulty.CompareTo(y.BeatmapSet.MaxStarDifficulty)); + break; + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 58a633b682..60017bfbd8 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -17,7 +17,6 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Transforms; using osu.Framework.Input; using osu.Framework.Screens; -using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Database; @@ -95,7 +94,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.X, Height = filter_height, - FilterChanged = () => filterChanged(), + FilterChanged = criteria => filterChanged(criteria), Exit = Exit, }); Add(beatmapInfoWedge = new BeatmapInfoWedge @@ -181,61 +180,9 @@ namespace osu.Game.Screens.Select protected abstract void OnSelected(); - private ScheduledDelegate filterTask; - - private void filterChanged(bool debounce = true, bool eagerSelection = true) + private void filterChanged(FilterCriteria criteria, bool debounce = true) { - if (!carousel.IsLoaded) return; - - if (Beatmap == null) return; - - filterTask?.Cancel(); - filterTask = Scheduler.AddDelayed(() => - { - filterTask = null; - var search = FilterControl.Search; - BeatmapGroup newSelection = null; - - carousel.Sort(FilterControl.Sort); - foreach (var beatmapGroup in carousel) - { - var set = beatmapGroup.BeatmapSet; - - bool hasCurrentMode = set.Beatmaps.Any(bm => bm.Mode == playMode); - - bool match = hasCurrentMode; - - match &= string.IsNullOrEmpty(search) - || (set.Metadata.Artist ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1 - || (set.Metadata.ArtistUnicode ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1 - || (set.Metadata.Title ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1 - || (set.Metadata.TitleUnicode ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1; - - if (match) - { - if (newSelection == null || beatmapGroup.BeatmapSet.OnlineBeatmapSetID == Beatmap.BeatmapSetInfo.OnlineBeatmapSetID) - { - if (newSelection != null) - newSelection.State = BeatmapGroupState.Collapsed; - newSelection = beatmapGroup; - } - else - beatmapGroup.State = BeatmapGroupState.Collapsed; - } - else - { - beatmapGroup.State = BeatmapGroupState.Hidden; - } - } - - if (newSelection != null) - { - if (newSelection.BeatmapPanels.Any(b => b.Beatmap.ID == Beatmap.BeatmapInfo.ID)) - carousel.SelectBeatmap(Beatmap.BeatmapInfo, false); - else if (eagerSelection) - carousel.SelectBeatmap(newSelection.BeatmapSet.Beatmaps[0], false); - } - }, debounce ? 250 : 0); + carousel.Filter(criteria, debounce); } private void onBeatmapSetAdded(BeatmapSetInfo s) => carousel.AddBeatmap(s); @@ -299,10 +246,7 @@ namespace osu.Game.Screens.Select initialAddSetsTask.Cancel(); } - private void playMode_ValueChanged(object sender, EventArgs e) - { - filterChanged(false); - } + private void playMode_ValueChanged(object sender, EventArgs e) => carousel.Filter(); private void changeBackground(WorkingBeatmap beatmap) { diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1864260e2c..2f6aa2734e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -197,6 +197,7 @@ + From c7fa79b027528c1a98829eb4dcfe2d7671af36d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 20:09:23 +0900 Subject: [PATCH 09/20] Fix nullref. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 20ebfb3837..b7405074ff 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -201,7 +201,7 @@ namespace osu.Game.Screens.Select computeYPositions(); - if (selectedGroup.State == BeatmapGroupState.Hidden) + if (selectedGroup == null || selectedGroup.State == BeatmapGroupState.Hidden) SelectNext(); }; From 6be80c95aed60006b0f3da521a981fab3aa45a67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 20:09:33 +0900 Subject: [PATCH 10/20] Preload song select from main menu. --- osu.Game/Screens/Menu/MainMenu.cs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 33bffef219..71730bc0eb 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -27,6 +27,7 @@ namespace osu.Game.Screens.Menu internal override bool ShowOverlays => buttons.State != MenuState.Initial; private BackgroundScreen background; + private Screen songSelect; protected override BackgroundScreen CreateBackground() => background; @@ -46,7 +47,7 @@ namespace osu.Game.Screens.Menu OnChart = delegate { Push(new ChartListing()); }, OnDirect = delegate { Push(new OnlineListing()); }, OnEdit = delegate { Push(new Editor()); }, - OnSolo = delegate { Push(new PlaySongSelect()); }, + OnSolo = delegate { Push(consumeSongSelect()); }, OnMulti = delegate { Push(new Lobby()); }, OnTest = delegate { Push(new TestBrowser()); }, OnExit = delegate { Exit(); }, @@ -62,6 +63,24 @@ namespace osu.Game.Screens.Menu background.LoadAsync(game); buttons.OnSettings = game.ToggleOptions; + + preloadSongSelect(); + } + + private void preloadSongSelect() + { + if (songSelect == null) + { + songSelect = new PlaySongSelect(); + songSelect.LoadAsync(Game); + } + } + + private Screen consumeSongSelect() + { + var s = songSelect; + songSelect = null; + return s; } protected override void OnEntering(Screen last) @@ -86,6 +105,9 @@ namespace osu.Game.Screens.Menu { base.OnResuming(last); + //we may have consumed our preloaded instance, so let's make another. + preloadSongSelect(); + const float length = 300; buttons.State = MenuState.TopLevel; From 0a03bdc428765b883032f614ec50a03985d8f1b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 20:44:02 +0900 Subject: [PATCH 11/20] Add missing license header. --- osu.Game/Screens/Select/FilterCriteria.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index f5afafa709..acf0954418 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps.Drawables; From 292de44a0b2fc0164a91dd2d6cd6c96309ffe38f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2017 22:41:07 +0900 Subject: [PATCH 12/20] WIP menu cursor. --- osu.Game.Modes.Osu/UI/OsuPlayfield.cs | 3 +- osu.Game/Graphics/Cursor/GameplayCursor.cs | 129 +++++++++++++++++++++ osu.Game/Graphics/Cursor/MenuCursor.cs | 106 +++++++++++++++++ osu.Game/OsuGameBase.cs | 2 +- osu.Game/osu.Game.csproj | 3 +- 5 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Graphics/Cursor/GameplayCursor.cs create mode 100644 osu.Game/Graphics/Cursor/MenuCursor.cs diff --git a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs index 7f7ec2d161..5caaaafb13 100644 --- a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs @@ -12,7 +12,6 @@ using osu.Game.Modes.UI; using System.Linq; using osu.Game.Graphics.Cursor; using osu.Game.Modes.Osu.Judgements; -using OpenTK.Graphics; namespace osu.Game.Modes.Osu.UI { @@ -63,7 +62,7 @@ namespace osu.Game.Modes.Osu.UI protected override void LoadComplete() { base.LoadComplete(); - AddInternal(new OsuCursorContainer { Colour = Color4.LightYellow }); + AddInternal(new GameplayCursor()); } public override void Add(DrawableHitObject h) diff --git a/osu.Game/Graphics/Cursor/GameplayCursor.cs b/osu.Game/Graphics/Cursor/GameplayCursor.cs new file mode 100644 index 0000000000..df31017734 --- /dev/null +++ b/osu.Game/Graphics/Cursor/GameplayCursor.cs @@ -0,0 +1,129 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; +using osu.Framework.Input; +using osu.Game.Configuration; +using System; + +namespace osu.Game.Graphics.Cursor +{ + public class GameplayCursor : CursorContainer + { + protected override Drawable CreateCursor() => new OsuCursor(); + + public GameplayCursor() + { + Add(new CursorTrail { Depth = 1 }); + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + ActiveCursor.Scale = new Vector2(1); + ActiveCursor.ScaleTo(1.2f, 100, EasingTypes.OutQuad); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + if (!state.Mouse.HasMainButtonPressed) + ActiveCursor.ScaleTo(1, 200, EasingTypes.OutQuad); + return base.OnMouseUp(state, args); + } + + public class OsuCursor : Container + { + private Container cursorContainer; + private Bindable cursorScale; + + public OsuCursor() + { + Origin = Anchor.Centre; + Size = new Vector2(42); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + cursorScale = config.GetBindable(OsuConfig.CursorSize); + + Children = new Drawable[] + { + cursorContainer = new CircularContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2((float)cursorScale), + Masking = true, + BorderThickness = Size.X / 6, + BorderColour = Color4.White, + EdgeEffect = new EdgeEffect { + Type = EdgeEffectType.Shadow, + Colour = Color4.Pink.Opacity(0.5f), + Radius = 5, + }, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + new CircularContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = Size.X / 3, + BorderColour = Color4.White.Opacity(0.5f), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + }, + }, + new CircularContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.1f), + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + }, + }, + } + }, + }; + cursorScale.ValueChanged += scaleChanged; + } + + private void scaleChanged(object sender, EventArgs e) + { + cursorContainer.Scale = new Vector2((float)cursorScale); + } + } + } +} diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs new file mode 100644 index 0000000000..ffdfd37a67 --- /dev/null +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -0,0 +1,106 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Game.Configuration; +using System; +using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.Transforms; + +namespace osu.Game.Graphics.Cursor +{ + public class MenuCursor : CursorContainer + { + protected override Drawable CreateCursor() => new Cursor(); + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + ActiveCursor.Scale = new Vector2(1); + ActiveCursor.ScaleTo(0.90f, 800, EasingTypes.OutQuint); + + ((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0; + ((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, EasingTypes.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + if (!state.Mouse.HasMainButtonPressed) + { + ((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, EasingTypes.OutQuint); + ActiveCursor.RotateTo(0, 200, EasingTypes.OutQuint); + ActiveCursor.ScaleTo(1, 500, EasingTypes.OutElastic); + } + + return base.OnMouseUp(state, args); + } + + protected override bool OnClick(InputState state) + { + ((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, EasingTypes.OutQuint); + + return base.OnClick(state); + } + + protected override bool OnDragStart(InputState state) + { + ActiveCursor.RotateTo(-30, 600, EasingTypes.OutElastic); + return base.OnDragStart(state); + } + + public class Cursor : Container + { + private Container cursorContainer; + private Bindable cursorScale; + + public Sprite AdditiveLayer; + + public Cursor() + { + Size = new Vector2(42); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config, TextureStore textures) + { + cursorScale = config.GetBindable(OsuConfig.CursorSize); + + Children = new Drawable[] + { + cursorContainer = new Container + { + Size = new Vector2(28), + Children = new Drawable[] + { + new Sprite + { + FillMode = FillMode.Fit, + Texture = textures.Get(@"Cursor/menu-cursor"), + }, + AdditiveLayer = new Sprite + { + FillMode = FillMode.Fit, + BlendingMode = BlendingMode.Additive, + Alpha = 0, + Texture = textures.Get(@"Cursor/menu-cursor"), + }, + } + } + }; + cursorScale.ValueChanged += scaleChanged; + } + + private void scaleChanged(object sender, EventArgs e) + { + cursorContainer.Scale = new Vector2((float)cursorScale); + } + } + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 50c8aab5ef..b815d0028f 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -137,7 +137,7 @@ namespace osu.Game { Children = new[] { - Cursor = new OsuCursorContainer { Depth = float.MinValue } + Cursor = new MenuCursor { Depth = float.MinValue } } }); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 80d5c906e0..8b0a5fd307 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -79,6 +79,7 @@ + @@ -221,7 +222,7 @@ - + From 7110ab8e17353800220ce8ee1a770d46b5603677 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2017 22:50:16 +0900 Subject: [PATCH 13/20] Stop cursor moving when paused. --- osu.Game/Screens/Play/PauseOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index b862adcd53..1cc6f9cf02 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -78,6 +78,8 @@ namespace osu.Game.Screens.Play // Don't let mouse down events through the overlay or people can click circles while paused. protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; + protected override bool OnMouseMove(InputState state) => true; + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Key == Key.Escape) From f9f31ca092b10ba89d4fce001ea056318258eb10 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Mar 2017 23:58:36 +0900 Subject: [PATCH 14/20] Add statefulness to MenuCursor. --- osu.Game/Graphics/Cursor/MenuCursor.cs | 14 ++++++++++++++ osu.Game/OsuGame.cs | 22 ++++++++++++++-------- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 2 ++ osu.Game/Screens/Menu/Intro.cs | 2 ++ osu.Game/Screens/OsuGameScreen.cs | 2 ++ osu.Game/Screens/Play/Player.cs | 6 +++++- 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index ffdfd37a67..ada1308b3e 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -55,6 +55,20 @@ namespace osu.Game.Graphics.Cursor return base.OnDragStart(state); } + protected override void PopIn() + { + ActiveCursor.FadeTo(1, 250, EasingTypes.OutQuint); + ActiveCursor.ScaleTo(1, 1000, EasingTypes.OutElastic); + } + + protected override void PopOut() + { + ActiveCursor.FadeTo(0, 1400, EasingTypes.OutQuint); + ActiveCursor.ScaleTo(1.1f, 100, EasingTypes.Out); + ActiveCursor.Delay(100); + ActiveCursor.ScaleTo(0, 500, EasingTypes.In); + } + public class Cursor : Container { private Container cursorContainer; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 8aa3a63d26..3896661835 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -220,7 +220,7 @@ namespace osu.Game } }; - Cursor.Alpha = 0; + Cursor.State = Visibility.Hidden; } private bool globalHotkeyPressed(InputState state, KeyDownEventArgs args) @@ -264,10 +264,20 @@ namespace osu.Game private Container overlayContent; + private OsuScreen currentScreen; + private void screenChanged(Screen newScreen) { + currentScreen = newScreen as OsuScreen; + + if (currentScreen == null) + { + Exit(); + return; + } + //central game mode change logic. - if ((newScreen as OsuScreen)?.ShowOverlays != true) + if (currentScreen.ShowOverlays != true) { Toolbar.State = Visibility.Hidden; musicController.State = Visibility.Hidden; @@ -278,13 +288,7 @@ namespace osu.Game Toolbar.State = Visibility.Visible; } - if (newScreen is MainMenu) - Cursor.FadeIn(100); - ScreenChanged?.Invoke(newScreen); - - if (newScreen == null) - Exit(); } protected override bool OnExiting() @@ -308,6 +312,8 @@ namespace osu.Game if (intro?.ChildScreen != null) intro.ChildScreen.Padding = new MarginPadding { Top = Toolbar.Position.Y + Toolbar.DrawHeight }; + + Cursor.State = currentScreen == null || currentScreen.HasLocalCursorDisplayed ? Visibility.Hidden : Visibility.Visible; } private void screenAdded(Screen newScreen) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b815d0028f..bfef31d14a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -38,7 +38,7 @@ namespace osu.Game private RatioAdjust ratioContainer; - protected CursorContainer Cursor; + protected MenuCursor Cursor; public readonly Bindable Beatmap = new Bindable(); diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 58e86bd069..6ae237f66c 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -21,6 +21,8 @@ namespace osu.Game.Screens.Menu internal override bool ShowOverlays => false; + internal override bool HasLocalCursorDisplayed => false; + public Disclaimer() { ValidForResume = false; diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 6d0cd4d821..6965707bcc 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -28,6 +28,8 @@ namespace osu.Game.Screens.Menu private SampleChannel seeya; private Track bgm; + internal override bool HasLocalCursorDisplayed => true; + internal override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty(); diff --git a/osu.Game/Screens/OsuGameScreen.cs b/osu.Game/Screens/OsuGameScreen.cs index 871d3a6780..736f9f96ae 100644 --- a/osu.Game/Screens/OsuGameScreen.cs +++ b/osu.Game/Screens/OsuGameScreen.cs @@ -24,6 +24,8 @@ namespace osu.Game.Screens protected new OsuGameBase Game => base.Game as OsuGameBase; + internal virtual bool HasLocalCursorDisplayed => false; + private readonly Bindable beatmap = new Bindable(); public WorkingBeatmap Beatmap diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 674a741d8c..bd54e6e263 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -32,6 +32,10 @@ namespace osu.Game.Screens.Play internal override bool ShowOverlays => false; + internal override bool HasLocalCursorDisplayed => !hasReplayLoaded && !IsPaused; + + private bool hasReplayLoaded => hitRenderer.InputManager.ReplayInputHandler != null; + public BeatmapInfo BeatmapInfo; public bool IsPaused { get; private set; } @@ -304,7 +308,7 @@ namespace osu.Game.Screens.Play { if (pauseOverlay == null) return false; - if (hitRenderer.InputManager.ReplayInputHandler != null) + if (hasReplayLoaded) return false; if (pauseOverlay.State != Visibility.Visible && !canPause) return true; From ba67e63ffa94e3a1265b4cefa3007d169ef6b760 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 20:53:20 +0900 Subject: [PATCH 15/20] Update resources. --- osu-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-resources b/osu-resources index 4f9ed4e703..07024c119a 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 4f9ed4e703777ede98737c7e2af31efa4694c395 +Subproject commit 07024c119a76fabb7822f4b1d68a8c9ed989d41a From 317dc94b4ca0c20e429f1a8deaf2c848f5fb5cd9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 21:04:46 +0900 Subject: [PATCH 16/20] Adjust appearance. --- osu-resources | 2 +- osu.Game/Graphics/Cursor/MenuCursor.cs | 7 ++++--- osu.Game/OsuGameBase.cs | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu-resources b/osu-resources index 07024c119a..f85c594c18 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 07024c119a76fabb7822f4b1d68a8c9ed989d41a +Subproject commit f85c594c182db2b01233e29ca52639b7baa00402 diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index ada1308b3e..1447fa9417 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -82,7 +82,7 @@ namespace osu.Game.Graphics.Cursor } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, TextureStore textures) + private void load(OsuConfigManager config, TextureStore textures, OsuColour colour) { cursorScale = config.GetBindable(OsuConfig.CursorSize); @@ -90,7 +90,7 @@ namespace osu.Game.Graphics.Cursor { cursorContainer = new Container { - Size = new Vector2(28), + Size = new Vector2(32), Children = new Drawable[] { new Sprite @@ -102,8 +102,9 @@ namespace osu.Game.Graphics.Cursor { FillMode = FillMode.Fit, BlendingMode = BlendingMode.Additive, + Colour = colour.Pink, Alpha = 0, - Texture = textures.Get(@"Cursor/menu-cursor"), + Texture = textures.Get(@"Cursor/menu-cursor-additive"), }, } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index bfef31d14a..f454956de7 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Game.Beatmaps; From 3e3cde01ef71dcbfad97eef9c7516a54e3f29248 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Mar 2017 21:21:16 +0900 Subject: [PATCH 17/20] Fix missing permitNulls. --- osu.Game/Screens/Select/FilterControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 9658509981..6dfee9e065 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -168,7 +168,7 @@ namespace osu.Game.Screens.Select private readonly Bindable playMode = new Bindable(); - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(permitNulls:true)] private void load(OsuColour colours, OsuGame osu) { sortTabs.AccentColour = colours.GreenLight; From 77067b7e64a3e419d0e431ef63f1d6455c0bfdd9 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Sat, 18 Mar 2017 02:03:44 +0900 Subject: [PATCH 18/20] Re-style. --- osu.Game/Graphics/Cursor/GameplayCursor.cs | 4 +++- osu.Game/OsuGame.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Cursor/GameplayCursor.cs b/osu.Game/Graphics/Cursor/GameplayCursor.cs index df31017734..a544a8e1bb 100644 --- a/osu.Game/Graphics/Cursor/GameplayCursor.cs +++ b/osu.Game/Graphics/Cursor/GameplayCursor.cs @@ -67,7 +67,8 @@ namespace osu.Game.Graphics.Cursor Masking = true, BorderThickness = Size.X / 6, BorderColour = Color4.White, - EdgeEffect = new EdgeEffect { + EdgeEffect = new EdgeEffect + { Type = EdgeEffectType.Shadow, Colour = Color4.Pink.Opacity(0.5f), Radius = 5, @@ -117,6 +118,7 @@ namespace osu.Game.Graphics.Cursor } }, }; + cursorScale.ValueChanged += scaleChanged; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 3896661835..9bd2ef9f75 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -277,7 +277,7 @@ namespace osu.Game } //central game mode change logic. - if (currentScreen.ShowOverlays != true) + if (!currentScreen.ShowOverlays) { Toolbar.State = Visibility.Hidden; musicController.State = Visibility.Hidden; From bcaf12e3d936145a2a23050716df5f5ff8973e56 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Sat, 18 Mar 2017 02:11:14 +0900 Subject: [PATCH 19/20] Rename Criteria -> CreateCriteria and make into method. --- osu.Game/Screens/Select/FilterControl.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 6dfee9e065..6fb05b8988 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Select if (sort != value) { sort = value; - FilterChanged?.Invoke(Criteria); + FilterChanged?.Invoke(CreateCriteria()); } } } @@ -51,12 +51,12 @@ namespace osu.Game.Screens.Select if (group != value) { group = value; - FilterChanged?.Invoke(Criteria); + FilterChanged?.Invoke(CreateCriteria()); } } } - public FilterCriteria Criteria => new FilterCriteria + public FilterCriteria CreateCriteria() => new FilterCriteria { Group = group, Sort = sort, @@ -96,7 +96,7 @@ namespace osu.Game.Screens.Select OnChange = (sender, newText) => { if (newText) - FilterChanged?.Invoke(Criteria); + FilterChanged?.Invoke(CreateCriteria()); }, Exit = () => Exit?.Invoke(), }, From 33d70b9bbcc1706cd3e2dae7533f374424d9c792 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Mar 2017 13:23:58 +0900 Subject: [PATCH 20/20] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index db310bfc10..169cb6485e 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit db310bfc10cd1c9ed12c9e19cdc0edfa53117353 +Subproject commit 169cb6485e7ae740a71cbcb7d0d9d08052eb8848