1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-16 10:17:36 +08:00
osu-lazer/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

197 lines
6.7 KiB
C#
Raw Normal View History

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2022-06-17 15:37:17 +08:00
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
2022-10-11 21:39:53 +08:00
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
2021-05-13 20:16:19 +08:00
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Screens.Edit.Compose.Components
{
public partial class EditorBlueprintContainer : BlueprintContainer<HitObject>
{
[Resolved]
protected EditorClock EditorClock { get; private set; }
[Resolved]
protected EditorBeatmap Beatmap { get; private set; }
protected readonly HitObjectComposer Composer;
2021-05-18 17:59:45 +08:00
private HitObjectUsageEventBuffer usageEventBuffer;
2022-10-11 21:39:53 +08:00
protected InputManager InputManager { get; private set; }
protected EditorBlueprintContainer(HitObjectComposer composer)
{
Composer = composer;
}
[BackgroundDependencyLoader]
private void load()
{
SelectedItems.BindTo(Beatmap.SelectedHitObjects);
}
protected override void LoadComplete()
{
base.LoadComplete();
2022-10-11 21:39:53 +08:00
InputManager = GetContainingInputManager();
Beatmap.HitObjectAdded += AddBlueprintFor;
Beatmap.HitObjectRemoved += RemoveBlueprintFor;
2023-11-20 20:34:36 +08:00
Beatmap.SelectedHitObjects.CollectionChanged += updateSelectionLifetime;
if (Composer != null)
{
foreach (var obj in Composer.HitObjects)
AddBlueprintFor(obj.HitObject);
2021-05-18 17:59:45 +08:00
usageEventBuffer = new HitObjectUsageEventBuffer(Composer.Playfield);
usageEventBuffer.HitObjectUsageBegan += AddBlueprintFor;
usageEventBuffer.HitObjectUsageFinished += RemoveBlueprintFor;
usageEventBuffer.HitObjectUsageTransferred += TransferBlueprintFor;
}
}
2021-05-18 17:59:45 +08:00
protected override void Update()
{
base.Update();
usageEventBuffer?.Update();
}
protected override IEnumerable<SelectionBlueprint<HitObject>> SortForMovement(IReadOnlyList<SelectionBlueprint<HitObject>> blueprints)
=> blueprints.OrderBy(b => b.Item.StartTime);
protected override bool ApplySnapResult(SelectionBlueprint<HitObject>[] blueprints, SnapResult result)
{
if (!base.ApplySnapResult(blueprints, result))
return false;
if (result.Time.HasValue)
{
// Apply the start time at the newly snapped-to position
double offset = result.Time.Value - blueprints.First().Item.StartTime;
if (offset != 0)
{
Beatmap.PerformOnSelection(obj =>
{
obj.StartTime += offset;
Beatmap.Update(obj);
});
}
}
return true;
}
protected override void AddBlueprintFor(HitObject item)
{
if (item is IBarLine)
return;
base.AddBlueprintFor(item);
}
/// <summary>
/// Invoked when a <see cref="HitObject"/> has been transferred to another <see cref="DrawableHitObject"/>.
/// </summary>
/// <param name="hitObject">The hit object which has been assigned to a new drawable.</param>
/// <param name="drawableObject">The new drawable that is representing the hit object.</param>
2021-05-13 20:16:19 +08:00
protected virtual void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject)
{
}
protected override void DragOperationCompleted()
{
base.DragOperationCompleted();
// handle positional change etc.
foreach (var blueprint in SelectionBlueprints)
Beatmap.Update(blueprint.Item);
}
protected override bool OnDoubleClick(DoubleClickEvent e)
{
if (!base.OnDoubleClick(e))
return false;
EditorClock?.SeekSmoothlyTo(ClickedBlueprint.Item.StartTime);
return true;
}
protected override IEnumerable<SelectionBlueprint<HitObject>> ApplySelectionOrder(IEnumerable<SelectionBlueprint<HitObject>> blueprints) =>
base.ApplySelectionOrder(blueprints)
.OrderBy(b => Math.Min(Math.Abs(EditorClock.CurrentTime - b.Item.GetEndTime()), Math.Abs(EditorClock.CurrentTime - b.Item.StartTime)));
protected override Container<SelectionBlueprint<HitObject>> CreateSelectionBlueprintContainer() => new HitObjectOrderedSelectionContainer { RelativeSizeAxes = Axes.Both };
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new EditorSelectionHandler();
protected override void SelectAll()
{
Composer.Playfield.KeepAllAlive();
SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).ToArray());
}
2023-11-20 20:34:36 +08:00
/// <summary>
/// Ensures that newly-selected hitobjects are kept alive
/// and drops that keep-alive from newly-deselected objects.
/// </summary>
private void updateSelectionLifetime(object sender, NotifyCollectionChangedEventArgs e)
{
2023-11-20 20:34:36 +08:00
if (e.NewItems != null)
{
foreach (HitObject newSelection in e.NewItems)
Composer.Playfield.SetKeepAlive(newSelection, true);
}
2023-11-20 20:34:36 +08:00
if (e.OldItems != null)
{
foreach (HitObject oldSelection in e.OldItems)
Composer.Playfield.SetKeepAlive(oldSelection, false);
}
}
protected override void OnBlueprintSelected(SelectionBlueprint<HitObject> blueprint)
{
base.OnBlueprintSelected(blueprint);
Composer.Playfield.SetKeepAlive(blueprint.Item, true);
}
protected override void OnBlueprintDeselected(SelectionBlueprint<HitObject> blueprint)
{
base.OnBlueprintDeselected(blueprint);
Composer.Playfield.SetKeepAlive(blueprint.Item, false);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (Beatmap != null)
{
Beatmap.HitObjectAdded -= AddBlueprintFor;
Beatmap.HitObjectRemoved -= RemoveBlueprintFor;
2023-11-20 20:34:36 +08:00
Beatmap.SelectedHitObjects.CollectionChanged -= updateSelectionLifetime;
}
2021-05-18 17:59:45 +08:00
usageEventBuffer?.Dispose();
}
}
}