diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index c2c1f6d602..aaf3517c9c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -12,12 +12,23 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Compose.Components; -using osuTK; +using Vector2 = osuTK.Vector2; namespace osu.Game.Rulesets.Osu.Edit { public class OsuSelectionHandler : EditorSelectionHandler { + /// + /// During a transform, the initial origin is stored so it can be used throughout the operation. + /// + private Vector2? referenceOrigin; + + /// + /// During a transform, the initial path types of a single selected slider are stored so they + /// can be maintained throughout the operation. + /// + private List referencePathTypes; + protected override void OnSelectionChanged() { base.OnSelectionChanged(); @@ -50,17 +61,6 @@ namespace osu.Game.Rulesets.Osu.Edit return true; } - /// - /// During a transform, the initial origin is stored so it can be used throughout the operation. - /// - private Vector2? referenceOrigin; - - /// - /// During a transform, the initial path types of a single selected slider are stored so they - /// can be maintained throughout the operation. - /// - private List referencePathTypes; - public override bool HandleReverse() { var hitObjects = EditorBeatmap.SelectedHitObjects; @@ -114,24 +114,10 @@ namespace osu.Game.Rulesets.Osu.Edit var hitObjects = selectedMovableObjects; var selectedObjectsQuad = getSurroundingQuad(hitObjects); - var centre = selectedObjectsQuad.Centre; foreach (var h in hitObjects) { - var pos = h.Position; - - switch (direction) - { - case Direction.Horizontal: - pos.X = centre.X - (pos.X - centre.X); - break; - - case Direction.Vertical: - pos.Y = centre.Y - (pos.Y - centre.Y); - break; - } - - h.Position = pos; + h.Position = GetFlippedPosition(direction, selectedObjectsQuad, h.Position); if (h is Slider slider) { @@ -204,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Edit { referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList(); - Quad sliderQuad = getSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value)); + Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value)); // Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0. scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size; @@ -333,7 +319,7 @@ namespace osu.Game.Rulesets.Osu.Edit /// /// The hit objects to calculate a quad for. private Quad getSurroundingQuad(OsuHitObject[] hitObjects) => - getSurroundingQuad(hitObjects.SelectMany(h => + GetSurroundingQuad(hitObjects.SelectMany(h => { if (h is IHasPath path) { @@ -348,30 +334,6 @@ namespace osu.Game.Rulesets.Osu.Edit return new[] { h.Position }; })); - /// - /// Returns a gamefield-space quad surrounding the provided points. - /// - /// The points to calculate a quad for. - private Quad getSurroundingQuad(IEnumerable points) - { - if (!EditorBeatmap.SelectedHitObjects.Any()) - return new Quad(); - - Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue); - Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue); - - // Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted - foreach (var p in points) - { - minPosition = Vector2.ComponentMin(minPosition, p); - maxPosition = Vector2.ComponentMax(maxPosition, p); - } - - Vector2 size = maxPosition - minPosition; - - return new Quad(minPosition.X, minPosition.Y, size.X, size.Y); - } - /// /// All osu! hitobjects which can be moved/rotated/scaled. /// diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 6d8ae69812..bfd5ab7afa 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -350,5 +350,55 @@ namespace osu.Game.Screens.Edit.Compose.Components => Enumerable.Empty(); #endregion + + #region Helper Methods + + /// + /// Given a flip direction, a surrounding quad for all selected objects, and a position, + /// will return the flipped position in screen space coordinates. + /// + protected static Vector2 GetFlippedPosition(Direction direction, Quad quad, Vector2 position) + { + var centre = quad.Centre; + + switch (direction) + { + case Direction.Horizontal: + position.X = centre.X - (position.X - centre.X); + break; + + case Direction.Vertical: + position.Y = centre.Y - (position.Y - centre.Y); + break; + } + + return position; + } + + /// + /// Returns a quad surrounding the provided points. + /// + /// The points to calculate a quad for. + protected static Quad GetSurroundingQuad(IEnumerable points) + { + if (!points.Any()) + return new Quad(); + + Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue); + Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue); + + // Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted + foreach (var p in points) + { + minPosition = Vector2.ComponentMin(minPosition, p); + maxPosition = Vector2.ComponentMax(maxPosition, p); + } + + Vector2 size = maxPosition - minPosition; + + return new Quad(minPosition.X, minPosition.Y, size.X, size.Y); + } + + #endregion } } diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index 7931a5ec41..2eb4ea107d 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs @@ -43,10 +43,16 @@ namespace osu.Game.Skinning.Editor public override bool HandleFlip(Direction direction) { - // TODO: this is temporary as well. - foreach (var c in SelectedBlueprints) + var selectionQuad = GetSurroundingQuad(SelectedBlueprints.Select(b => b.ScreenSpaceSelectionPoint)); + + foreach (var b in SelectedBlueprints) { - ((Drawable)c.Item).Scale *= new Vector2( + var drawableItem = (Drawable)b.Item; + + drawableItem.Position = + drawableItem.Parent.ToLocalSpace(GetFlippedPosition(direction, selectionQuad, b.ScreenSpaceSelectionPoint)) - drawableItem.AnchorPosition; + + drawableItem.Scale *= new Vector2( direction == Direction.Horizontal ? -1 : 1, direction == Direction.Vertical ? -1 : 1 );