mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 02:22:56 +08:00
Migrate osu! rotation handling to SelectionRotationHandler
This commit is contained in:
parent
ba8ebefb50
commit
ba904fd77b
@ -28,11 +28,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IDistanceSnapProvider? snapProvider { get; set; }
|
private IDistanceSnapProvider? snapProvider { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
|
||||||
/// </summary>
|
|
||||||
private Vector2? referenceOrigin;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// During a transform, the initial path types of a single selected slider are stored so they
|
/// During a transform, the initial path types of a single selected slider are stored so they
|
||||||
/// can be maintained throughout the operation.
|
/// can be maintained throughout the operation.
|
||||||
@ -54,7 +49,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
protected override void OnOperationEnded()
|
protected override void OnOperationEnded()
|
||||||
{
|
{
|
||||||
base.OnOperationEnded();
|
base.OnOperationEnded();
|
||||||
referenceOrigin = null;
|
|
||||||
referencePathTypes = null;
|
referencePathTypes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,28 +164,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
if ((reference & Anchor.y0) > 0) scale.Y = -scale.Y;
|
if ((reference & Anchor.y0) > 0) scale.Y = -scale.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleRotation(float delta)
|
public override SelectionRotationHandler CreateRotationHandler() => new OsuSelectionRotationHandler(ChangeHandler)
|
||||||
{
|
{
|
||||||
var hitObjects = selectedMovableObjects;
|
SelectedItems = { BindTarget = SelectedItems }
|
||||||
|
};
|
||||||
Quad quad = GeometryUtils.GetSurroundingQuad(hitObjects);
|
|
||||||
|
|
||||||
referenceOrigin ??= quad.Centre;
|
|
||||||
|
|
||||||
foreach (var h in hitObjects)
|
|
||||||
{
|
|
||||||
h.Position = GeometryUtils.RotatePointAroundOrigin(h.Position, referenceOrigin.Value, delta);
|
|
||||||
|
|
||||||
if (h is IHasPath path)
|
|
||||||
{
|
|
||||||
foreach (PathControlPoint cp in path.Path.ControlPoints)
|
|
||||||
cp.Position = GeometryUtils.RotatePointAroundOrigin(cp.Position, Vector2.Zero, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this isn't always the case but let's be lenient for now.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scaleSlider(Slider slider, Vector2 scale)
|
private void scaleSlider(Slider slider, Vector2 scale)
|
||||||
{
|
{
|
||||||
|
98
osu.Game.Rulesets.Osu/Edit/OsuSelectionRotationHandler.cs
Normal file
98
osu.Game.Rulesets.Osu/Edit/OsuSelectionRotationHandler.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
|
{
|
||||||
|
public class OsuSelectionRotationHandler : SelectionRotationHandler
|
||||||
|
{
|
||||||
|
private readonly IEditorChangeHandler? changeHandler;
|
||||||
|
|
||||||
|
public BindableList<HitObject> SelectedItems { get; } = new BindableList<HitObject>();
|
||||||
|
|
||||||
|
public OsuSelectionRotationHandler(IEditorChangeHandler? changeHandler)
|
||||||
|
{
|
||||||
|
this.changeHandler = changeHandler;
|
||||||
|
|
||||||
|
SelectedItems.CollectionChanged += (_, __) => updateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
|
||||||
|
CanRotate.Value = quad.Width > 0 || quad.Height > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OsuHitObject[]? objectsInRotation;
|
||||||
|
|
||||||
|
private Vector2? defaultOrigin;
|
||||||
|
private Dictionary<OsuHitObject, Vector2>? originalPositions;
|
||||||
|
private Dictionary<IHasPath, Vector2[]>? originalPathControlPointPositions;
|
||||||
|
|
||||||
|
public override void Begin()
|
||||||
|
{
|
||||||
|
if (objectsInRotation != null)
|
||||||
|
throw new InvalidOperationException($"Cannot {nameof(Begin)} a rotate operation while another is in progress!");
|
||||||
|
|
||||||
|
changeHandler?.BeginChange();
|
||||||
|
|
||||||
|
objectsInRotation = selectedMovableObjects.ToArray();
|
||||||
|
defaultOrigin = GeometryUtils.GetSurroundingQuad(objectsInRotation).Centre;
|
||||||
|
originalPositions = objectsInRotation.ToDictionary(obj => obj, obj => obj.Position);
|
||||||
|
originalPathControlPointPositions = objectsInRotation.OfType<IHasPath>().ToDictionary(
|
||||||
|
obj => obj,
|
||||||
|
obj => obj.Path.ControlPoints.Select(point => point.Position).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float rotation, Vector2? origin = null)
|
||||||
|
{
|
||||||
|
if (objectsInRotation == null)
|
||||||
|
throw new InvalidOperationException($"Cannot {nameof(Update)} a rotate operation without calling {nameof(Begin)} first!");
|
||||||
|
|
||||||
|
Debug.Assert(originalPositions != null && originalPathControlPointPositions != null && defaultOrigin != null);
|
||||||
|
|
||||||
|
Vector2 actualOrigin = origin ?? defaultOrigin.Value;
|
||||||
|
|
||||||
|
foreach (var ho in objectsInRotation)
|
||||||
|
{
|
||||||
|
ho.Position = GeometryUtils.RotatePointAroundOrigin(originalPositions[ho], actualOrigin, rotation);
|
||||||
|
|
||||||
|
if (ho is IHasPath withPath)
|
||||||
|
{
|
||||||
|
var originalPath = originalPathControlPointPositions[withPath];
|
||||||
|
|
||||||
|
for (int i = 0; i < withPath.Path.ControlPoints.Count; ++i)
|
||||||
|
withPath.Path.ControlPoints[i].Position = GeometryUtils.RotatePointAroundOrigin(originalPath[i], Vector2.Zero, rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Commit()
|
||||||
|
{
|
||||||
|
if (objectsInRotation == null)
|
||||||
|
throw new InvalidOperationException($"Cannot {nameof(Commit)} a rotate operation without calling {nameof(Begin)} first!");
|
||||||
|
|
||||||
|
changeHandler?.EndChange();
|
||||||
|
|
||||||
|
objectsInRotation = null;
|
||||||
|
originalPositions = null;
|
||||||
|
originalPathControlPointPositions = null;
|
||||||
|
defaultOrigin = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<OsuHitObject> selectedMovableObjects => SelectedItems.Cast<OsuHitObject>()
|
||||||
|
.Where(h => h is not Spinner);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user