Skip to content

Commit

Permalink
Merge pull request #29039 from bdach/multiple-selection-sample-popover
Browse files Browse the repository at this point in the history
Make sample popover change properties of all samples in multiple selection
  • Loading branch information
peppy authored Jul 24, 2024
2 parents 6e46256 + 1ed7e4b commit 4983e5f
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,70 @@ public void TestHotkeysDuringPlacement()
void checkPlacementSample(string expected) => AddAssert($"Placement sample is {expected}", () => EditorBeatmap.PlacementObject.Value.Samples.First().Bank, () => Is.EqualTo(expected));
}

[Test]
public void PopoverForMultipleSelectionChangesAllSamples()
{
AddStep("add slider", () =>
{
EditorBeatmap.Add(new Slider
{
Position = new Vector2(256, 256),
StartTime = 1000,
Path = new SliderPath(new[] { new PathControlPoint(Vector2.Zero), new PathControlPoint(new Vector2(250, 0)) }),
Samples =
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
},
NodeSamples = new List<IList<HitSampleInfo>>
{
new List<HitSampleInfo>
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM),
new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM),
},
new List<HitSampleInfo>
{
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT),
new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT),
},
}
});
});
AddStep("select everything", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));

clickSamplePiece(0);

setBankViaPopover(HitSampleInfo.BANK_DRUM);
samplePopoverHasSingleBank(HitSampleInfo.BANK_DRUM);
hitObjectHasSampleNormalBank(0, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleNormalBank(1, HitSampleInfo.BANK_DRUM);
hitObjectHasSampleNormalBank(2, HitSampleInfo.BANK_DRUM);
hitObjectNodeHasSampleNormalBank(2, 0, HitSampleInfo.BANK_DRUM);
hitObjectNodeHasSampleNormalBank(2, 1, HitSampleInfo.BANK_DRUM);

setVolumeViaPopover(30);
samplePopoverHasSingleVolume(30);
hitObjectHasSampleVolume(0, 30);
hitObjectHasSampleVolume(1, 30);
hitObjectHasSampleVolume(2, 30);
hitObjectNodeHasSampleVolume(2, 0, 30);
hitObjectNodeHasSampleVolume(2, 1, 30);

toggleAdditionViaPopover(0);
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
hitObjectHasSamples(1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
hitObjectHasSamples(2, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
hitObjectNodeHasSamples(2, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP, HitSampleInfo.HIT_WHISTLE);
hitObjectNodeHasSamples(2, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);

setAdditionBankViaPopover(HitSampleInfo.BANK_SOFT);
hitObjectHasSampleAdditionBank(0, HitSampleInfo.BANK_SOFT);
hitObjectHasSampleAdditionBank(1, HitSampleInfo.BANK_SOFT);
hitObjectHasSampleAdditionBank(2, HitSampleInfo.BANK_SOFT);
hitObjectNodeHasSampleAdditionBank(2, 0, HitSampleInfo.BANK_SOFT);
hitObjectNodeHasSampleAdditionBank(2, 1, HitSampleInfo.BANK_SOFT);
}

[Test]
public void TestHotkeysAffectNodeSamples()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ public partial class NodeSampleEditPopover : SampleEditPopover
{
private readonly int nodeIndex;

protected override IList<HitSampleInfo> GetRelevantSamples(HitObject ho)
protected override IEnumerable<(HitObject hitObject, IList<HitSampleInfo> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -106,15 +107,34 @@ public partial class SampleEditPopover : OsuPopover
private FillFlowContainer togglesCollection = null!;

private HitObject[] relevantObjects = null!;
private IList<HitSampleInfo>[] allRelevantSamples = null!;
private (HitObject hitObject, IList<HitSampleInfo> samples)[] allRelevantSamples = null!;

/// <summary>
/// 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.
/// </summary>
/// <param name="ho">The hit object to get the relevant samples from.</param>
/// <param name="hitObjects">The hit objects to get the relevant samples from.</param>
/// <returns>The relevant list of samples.</returns>
protected virtual IList<HitSampleInfo> GetRelevantSamples(HitObject ho) => ho.Samples;
protected virtual IEnumerable<(HitObject hitObject, IList<HitSampleInfo> 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!;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<string>().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()
{
Expand All @@ -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
Expand All @@ -247,9 +277,8 @@ private void updateAllRelevantSamples(Action<HitObject, IList<HitSampleInfo>> 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);
}
Expand Down Expand Up @@ -333,7 +362,7 @@ private void updateTernaryStates()
{
foreach ((string sampleName, var bindable) in selectionSampleStates)
{
bindable.Value = SelectionHandler<HitObject>.GetStateFromSelection(relevantObjects, h => GetRelevantSamples(h).Any(s => s.Name == sampleName));
bindable.Value = SelectionHandler<HitObject>.GetStateFromSelection(GetRelevantSamples(relevantObjects), h => h.samples.Any(s => s.Name == sampleName));
}
}

Expand Down

0 comments on commit 4983e5f

Please sign in to comment.