diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/NodeSamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/NodeSamplePointPiece.cs index ae3838bc413e..9cc1268db7ab 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/NodeSamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/NodeSamplePointPiece.cs @@ -34,12 +34,12 @@ public partial class NodeSampleEditPopover : SampleEditPopover { private readonly int nodeIndex; - protected override IList GetRelevantSamples(HitObject ho) + protected override IEnumerable<(HitObject hitObject, IList samples)> GetRelevantSamples(HitObject[] hitObjects) { - if (ho is not IHasRepeats hasRepeats) - return ho.Samples; + if (hitObjects.Length > 1 || hitObjects[0] is not IHasRepeats hasRepeats) + return base.GetRelevantSamples(hitObjects); - return nodeIndex < hasRepeats.NodeSamples.Count ? hasRepeats.NodeSamples[nodeIndex] : ho.Samples; + return [(hitObjects[0], nodeIndex < hasRepeats.NodeSamples.Count ? hasRepeats.NodeSamples[nodeIndex] : hitObjects[0].Samples)]; } public NodeSampleEditPopover(HitObject hitObject, int nodeIndex) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 8c7603021a0b..8bfb0a33587d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -21,6 +21,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Screens.Edit.Timing; using osuTK; using osuTK.Graphics; @@ -106,15 +107,34 @@ public partial class SampleEditPopover : OsuPopover private FillFlowContainer togglesCollection = null!; private HitObject[] relevantObjects = null!; - private IList[] allRelevantSamples = null!; + private (HitObject hitObject, IList samples)[] allRelevantSamples = null!; /// /// Gets the sub-set of samples relevant to this sample point piece. /// For example, to edit node samples this should return the samples at the index of the node. /// - /// The hit object to get the relevant samples from. + /// The hit objects to get the relevant samples from. /// The relevant list of samples. - protected virtual IList GetRelevantSamples(HitObject ho) => ho.Samples; + protected virtual IEnumerable<(HitObject hitObject, IList samples)> GetRelevantSamples(HitObject[] hitObjects) + { + if (hitObjects.Length == 1) + { + yield return (hitObjects[0], hitObjects[0].Samples); + + yield break; + } + + foreach (var ho in hitObjects) + { + yield return (ho, ho.Samples); + + if (ho is IHasRepeats hasRepeats) + { + foreach (var node in hasRepeats.NodeSamples) + yield return (ho, node); + } + } + } [Resolved(canBeNull: true)] private EditorBeatmap beatmap { get; set; } = null!; @@ -172,7 +192,7 @@ private void load() // if the piece belongs to a currently selected object, assume that the user wants to change all selected objects. // if the piece belongs to an unselected object, operate on that object alone, independently of the selection. relevantObjects = (beatmap.SelectedHitObjects.Contains(hitObject) ? beatmap.SelectedHitObjects : hitObject.Yield()).ToArray(); - allRelevantSamples = relevantObjects.Select(GetRelevantSamples).ToArray(); + allRelevantSamples = GetRelevantSamples(relevantObjects).ToArray(); // even if there are multiple objects selected, we can still display sample volume or bank if they all have the same value. int? commonVolume = getCommonVolume(); @@ -214,9 +234,19 @@ private void load() togglesCollection.AddRange(createTernaryButtons().Select(b => new DrawableTernaryButton(b) { RelativeSizeAxes = Axes.None, Size = new Vector2(40, 40) })); } - private string? getCommonBank() => allRelevantSamples.Select(GetBankValue).Distinct().Count() == 1 ? GetBankValue(allRelevantSamples.First()) : null; - private string? getCommonAdditionBank() => allRelevantSamples.Select(GetAdditionBankValue).Where(o => o is not null).Distinct().Count() == 1 ? GetAdditionBankValue(allRelevantSamples.First()) : null; - private int? getCommonVolume() => allRelevantSamples.Select(GetVolumeValue).Distinct().Count() == 1 ? GetVolumeValue(allRelevantSamples.First()) : null; + private string? getCommonBank() => allRelevantSamples.Select(h => GetBankValue(h.samples)).Distinct().Count() == 1 + ? GetBankValue(allRelevantSamples.First().samples) + : null; + + private string? getCommonAdditionBank() + { + string[] additionBanks = allRelevantSamples.Select(h => GetAdditionBankValue(h.samples)).Where(o => o is not null).Cast().Distinct().ToArray(); + return additionBanks.Length == 1 ? additionBanks[0] : null; + } + + private int? getCommonVolume() => allRelevantSamples.Select(h => GetVolumeValue(h.samples)).Distinct().Count() == 1 + ? GetVolumeValue(allRelevantSamples.First().samples) + : null; private void updatePrimaryBankState() { @@ -231,7 +261,7 @@ private void updateAdditionBankState() additionBank.PlaceholderText = string.IsNullOrEmpty(commonAdditionBank) ? "(multiple)" : string.Empty; additionBank.Current.Value = commonAdditionBank; - bool anyAdditions = allRelevantSamples.Any(o => o.Any(s => s.Name != HitSampleInfo.HIT_NORMAL)); + bool anyAdditions = allRelevantSamples.Any(o => o.samples.Any(s => s.Name != HitSampleInfo.HIT_NORMAL)); if (anyAdditions) additionBank.Show(); else @@ -247,9 +277,8 @@ private void updateAllRelevantSamples(Action> up { beatmap.BeginChange(); - foreach (var relevantHitObject in relevantObjects) + foreach (var (relevantHitObject, relevantSamples) in GetRelevantSamples(relevantObjects)) { - var relevantSamples = GetRelevantSamples(relevantHitObject); updateAction(relevantHitObject, relevantSamples); beatmap.Update(relevantHitObject); } @@ -333,7 +362,7 @@ private void updateTernaryStates() { foreach ((string sampleName, var bindable) in selectionSampleStates) { - bindable.Value = SelectionHandler.GetStateFromSelection(relevantObjects, h => GetRelevantSamples(h).Any(s => s.Name == sampleName)); + bindable.Value = SelectionHandler.GetStateFromSelection(GetRelevantSamples(relevantObjects), h => h.samples.Any(s => s.Name == sampleName)); } }