private void workingBeatmapChanged(ValueChangedEvent <WorkingBeatmap> e) { if (e.NewValue is DummyWorkingBeatmap || !this.IsCurrentScreen()) { return; } Logger.Log($"working beatmap updated to {e.NewValue}"); if (!Carousel.SelectBeatmap(e.NewValue.BeatmapInfo, false)) { // A selection may not have been possible with filters applied. // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. if (e.NewValue.BeatmapInfo.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; transferRulesetValue(); } // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), // we still want to temporarily show the new beatmap, bypassing filters. // This will be undone the next time the user changes the filter. var criteria = FilterControl.CreateCriteria(); criteria.SelectedBeatmapSet = e.NewValue.BeatmapInfo.BeatmapSet; Carousel.Filter(criteria); Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); } }
private void carouselBeatmapsLoaded() { bindBindables(); // If a selection was already obtained, do not attempt to update the selected beatmap. if (Carousel.SelectedBeatmapSet != null) { return; } // Attempt to select the current beatmap on the carousel, if it is valid to be selected. if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) { return; } // If the current active beatmap could not be selected, select a new random beatmap. if (!Carousel.SelectNextRandom()) { // in the case random selection failed, we want to trigger selectionChanged // to show the dummy beatmap (we have nothing else to display). performUpdateSelected(); } }
private void carouselBeatmapsLoaded() { bindBindables(); // If a selection was already obtained, do not attempt to update the selected beatmap. if (Carousel.SelectedBeatmapSet != null) { return; } // Attempt to select the current beatmap on the carousel, if it is valid to be selected. if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) { if (Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) { return; } // prefer not changing ruleset at this point, so look for another difficulty in the currently playing beatmap var found = Beatmap.Value.BeatmapSetInfo.Beatmaps.FirstOrDefault(b => b.Ruleset.Equals(decoupledRuleset.Value)); if (found != null && Carousel.SelectBeatmap(found, false)) { return; } } // If the current active beatmap could not be selected, select a new random beatmap. if (!Carousel.SelectNextRandom()) { // in the case random selection failed, we want to trigger selectionChanged // to show the dummy beatmap (we have nothing else to display). performUpdateSelected(); } }
/// <summary> /// Call to make a selection and perform the default action for this SongSelect. /// </summary> /// <param name="beatmap">An optional beatmap to override the current carousel selection.</param> /// <param name="ruleset">An optional ruleset to override the current carousel selection.</param> /// <param name="customStartAction">An optional custom action to perform instead of <see cref="OnStart"/>.</param> public void FinaliseSelection(BeatmapInfo beatmap = null, RulesetInfo ruleset = null, Action customStartAction = null) { // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) { return; } if (ruleset != null) { Ruleset.Value = ruleset; } transferRulesetValue(); // while transferRulesetValue will flush, it only does so if the ruleset changes. // the user could have changed a filter, and we want to ensure we are 100% up-to-date and consistent here. Carousel.FlushPendingFilterOperations(); // avoid attempting to continue before a selection has been obtained. // this could happen via a user interaction while the carousel is still in a loading state. if (Carousel.SelectedBeatmap == null) { return; } if (beatmap != null) { Carousel.SelectBeatmap(beatmap); } if (selectionChangedDebounce?.Completed == false) { selectionChangedDebounce.RunTask(); selectionChangedDebounce?.Cancel(); // cancel the already scheduled task. selectionChangedDebounce = null; } if (customStartAction != null) { customStartAction(); Carousel.AllowSelection = false; } else if (OnStart()) { Carousel.AllowSelection = false; } }
private void workingBeatmapChanged(ValueChangedEvent <WorkingBeatmap> e) { if (e.NewValue is DummyWorkingBeatmap) { return; } if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false)) { // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); } } }
private void workingBeatmapChanged(ValueChangedEvent <WorkingBeatmap> e) { if (e.NewValue is DummyWorkingBeatmap || !this.IsCurrentScreen()) { return; } if (!Carousel.SelectBeatmap(e.NewValue.BeatmapInfo, false)) { // A selection may not have been possible with filters applied. // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. if (e.NewValue.BeatmapInfo.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; transferRulesetValue(); } // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), // we still want to forcefully show the new beatmap, bypassing filters. Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); } }
/// <summary> /// Call to make a selection and perform the default action for this SongSelect. /// </summary> /// <param name="beatmap">An optional beatmap to override the current carousel selection.</param> /// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param> public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true) { // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) { return; } // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). Carousel.FlushPendingFilterOperations(); // avoid attempting to continue before a selection has been obtained. // this could happen via a user interaction while the carousel is still in a loading state. if (Carousel.SelectedBeatmap == null) { return; } if (beatmap != null) { Carousel.SelectBeatmap(beatmap); } if (selectionChangedDebounce?.Completed == false) { selectionChangedDebounce.RunTask(); selectionChangedDebounce.Cancel(); // cancel the already scheduled task. selectionChangedDebounce = null; } if (performStartAction) { OnStart(); } }
/// <summary> /// Selection has been changed as the result of a user interaction. /// </summary> private void performUpdateSelected() { var beatmap = beatmapNoDebounce; var ruleset = rulesetNoDebounce; selectionChangedDebounce?.Cancel(); if (beatmapNoDebounce == null) { run(); } else { selectionChangedDebounce = Scheduler.AddDelayed(run, 200); } void run() { // clear pending task immediately to track any potential nested debounce operation. selectionChangedDebounce = null; Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ID.ToString() ?? "null"}"); if (transferRulesetValue()) { Mods.Value = Array.Empty <Mod>(); // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). if (beatmap != null && !Carousel.SelectBeatmap(beatmap, false)) { beatmap = null; } } if (selectionChangedDebounce != null) { // a new nested operation was started; switch to it for further selection. // this avoids having two separate debounces trigger from the same source. selectionChangedDebounce.RunTask(); return; } // We may be arriving here due to another component changing the bindable Beatmap. // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. if (!EqualityComparer <BeatmapInfo> .Default.Equals(beatmap, Beatmap.Value.BeatmapInfo)) { Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\""); WorkingBeatmap previous = Beatmap.Value; Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); if (beatmap != null) { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) { sampleChangeDifficulty.Play(); } else { sampleChangeBeatmap.Play(); } } } if (this.IsCurrentScreen()) { ensurePlayingSelected(); } updateComponentFromBeatmap(Beatmap.Value); } }