Centralise cases of performing actions on the current selection

By moving this to a central location, we can avoid invoking the
EditorChangeHandler when there is no selection made. This helps
alleviate the issue pointed out in
https://github.com/ppy/osu/issues/11901, but not fix it completely.
This commit is contained in:
Dean Herbert 2021-02-26 14:15:12 +09:00
parent 119b4e8174
commit cd1c1bf534
5 changed files with 42 additions and 44 deletions

View File

@ -45,6 +45,7 @@ namespace osu.Game.Rulesets.Mania.Edit
int minColumn = int.MaxValue;
int maxColumn = int.MinValue;
// find min/max in an initial pass before actually performing the movement.
foreach (var obj in EditorBeatmap.SelectedHitObjects.OfType<ManiaHitObject>())
{
if (obj.Column < minColumn)
@ -55,8 +56,11 @@ namespace osu.Game.Rulesets.Mania.Edit
columnDelta = Math.Clamp(columnDelta, -minColumn, maniaPlayfield.TotalColumns - 1 - maxColumn);
foreach (var obj in EditorBeatmap.SelectedHitObjects.OfType<ManiaHitObject>())
obj.Column += columnDelta;
EditorBeatmap.PerformOnSelection(h =>
{
if (h is ManiaHitObject maniaObj)
maniaObj.Column += columnDelta;
});
}
}
}

View File

@ -52,32 +52,24 @@ namespace osu.Game.Rulesets.Taiko.Edit
public void SetStrongState(bool state)
{
var hits = EditorBeatmap.SelectedHitObjects.OfType<Hit>();
EditorBeatmap.BeginChange();
foreach (var h in hits)
EditorBeatmap.PerformOnSelection(h =>
{
if (h.IsStrong != state)
{
h.IsStrong = state;
EditorBeatmap.Update(h);
}
}
if (!(h is Hit taikoHit)) return;
EditorBeatmap.EndChange();
if (taikoHit.IsStrong != state)
{
taikoHit.IsStrong = state;
EditorBeatmap.Update(taikoHit);
}
});
}
public void SetRimState(bool state)
{
var hits = EditorBeatmap.SelectedHitObjects.OfType<Hit>();
EditorBeatmap.BeginChange();
foreach (var h in hits)
h.Type = state ? HitType.Rim : HitType.Centre;
EditorBeatmap.EndChange();
EditorBeatmap.PerformOnSelection(h =>
{
if (h is Hit taikoHit) taikoHit.Type = state ? HitType.Rim : HitType.Centre;
});
}
protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint> selection)

View File

@ -495,8 +495,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
// Apply the start time at the newly snapped-to position
double offset = result.Time.Value - movementBlueprints.First().HitObject.StartTime;
foreach (HitObject obj in Beatmap.SelectedHitObjects)
obj.StartTime += offset;
Beatmap.PerformOnSelection(obj => obj.StartTime += offset);
}
return true;

View File

@ -320,18 +320,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// <param name="sampleName">The name of the hit sample.</param>
public void AddHitSample(string sampleName)
{
EditorBeatmap.BeginChange();
foreach (var h in EditorBeatmap.SelectedHitObjects)
EditorBeatmap.PerformOnSelection(h =>
{
// Make sure there isn't already an existing sample
if (h.Samples.Any(s => s.Name == sampleName))
continue;
return;
h.Samples.Add(new HitSampleInfo(sampleName));
}
EditorBeatmap.EndChange();
});
}
/// <summary>
@ -341,19 +337,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// <exception cref="InvalidOperationException">Throws if any selected object doesn't implement <see cref="IHasComboInformation"/></exception>
public void SetNewCombo(bool state)
{
EditorBeatmap.BeginChange();
foreach (var h in EditorBeatmap.SelectedHitObjects)
EditorBeatmap.PerformOnSelection(h =>
{
var comboInfo = h as IHasComboInformation;
if (comboInfo == null || comboInfo.NewCombo == state) continue;
if (comboInfo == null || comboInfo.NewCombo == state) return;
comboInfo.NewCombo = state;
EditorBeatmap.Update(h);
}
EditorBeatmap.EndChange();
});
}
/// <summary>
@ -362,12 +354,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// <param name="sampleName">The name of the hit sample.</param>
public void RemoveHitSample(string sampleName)
{
EditorBeatmap.BeginChange();
foreach (var h in EditorBeatmap.SelectedHitObjects)
h.SamplesBindable.RemoveAll(s => s.Name == sampleName);
EditorBeatmap.EndChange();
EditorBeatmap.PerformOnSelection(h => h.SamplesBindable.RemoveAll(s => s.Name == sampleName));
}
#endregion

View File

@ -100,6 +100,22 @@ namespace osu.Game.Screens.Edit
private readonly HashSet<HitObject> batchPendingUpdates = new HashSet<HitObject>();
/// <summary>
/// Perform the provided action on every selected hitobject.
/// Changes will be grouped as one history action.
/// </summary>
/// <param name="action">The action to perform.</param>
public void PerformOnSelection(Action<HitObject> action)
{
if (SelectedHitObjects.Count == 0)
return;
BeginChange();
foreach (var h in SelectedHitObjects)
action(h);
EndChange();
}
/// <summary>
/// Adds a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>.
/// </summary>