diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
index c7be921a4e..a2642bda83 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
@@ -5,7 +5,6 @@
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
-using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
@@ -16,24 +15,22 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuSelectionHandler : SelectionHandler
{
- public override ComposeSelectionBox CreateSelectionBox()
- => new ComposeSelectionBox
- {
- CanRotate = true,
- CanScaleX = true,
- CanScaleY = true,
+ protected override void OnSelectionChanged()
+ {
+ base.OnSelectionChanged();
- OperationStarted = () => ChangeHandler.BeginChange(),
- OperationEnded = () =>
- {
- ChangeHandler.EndChange();
- referenceOrigin = null;
- },
+ bool canOperate = SelectedHitObjects.Count() > 1 || SelectedHitObjects.Any(s => s is Slider);
- OnRotation = e => rotateSelection(e.Delta.X),
- OnScaleX = handleScaleX,
- OnScaleY = handleScaleY,
- };
+ SelectionBox.CanRotate = canOperate;
+ SelectionBox.CanScaleX = canOperate;
+ SelectionBox.CanScaleY = canOperate;
+ }
+
+ protected override void OnDragOperationEnded()
+ {
+ base.OnDragOperationEnded();
+ referenceOrigin = null;
+ }
public override bool HandleMovement(MoveSelectionEvent moveEvent) =>
moveSelection(moveEvent.InstantDelta);
@@ -43,35 +40,35 @@ public override bool HandleMovement(MoveSelectionEvent moveEvent) =>
///
private Vector2? referenceOrigin;
- private void handleScaleY(DragEvent e, Anchor reference)
+ public override bool HandleScaleY(in float scale, Anchor reference)
{
int direction = (reference & Anchor.y0) > 0 ? -1 : 1;
if (direction < 0)
{
// when resizing from a top drag handle, we want to move the selection first
- if (!moveSelection(new Vector2(0, e.Delta.Y)))
- return;
+ if (!moveSelection(new Vector2(0, scale)))
+ return false;
}
- scaleSelection(new Vector2(0, direction * e.Delta.Y));
+ return scaleSelection(new Vector2(0, direction * scale));
}
- private void handleScaleX(DragEvent e, Anchor reference)
+ public override bool HandleScaleX(in float scale, Anchor reference)
{
int direction = (reference & Anchor.x0) > 0 ? -1 : 1;
if (direction < 0)
{
// when resizing from a left drag handle, we want to move the selection first
- if (!moveSelection(new Vector2(e.Delta.X, 0)))
- return;
+ if (!moveSelection(new Vector2(scale, 0)))
+ return false;
}
- scaleSelection(new Vector2(direction * e.Delta.X, 0));
+ return scaleSelection(new Vector2(direction * scale, 0));
}
- private bool rotateSelection(in float delta)
+ public override bool HandleRotation(float delta)
{
Quad quad = getSelectionQuad();
@@ -96,6 +93,7 @@ private bool rotateSelection(in float delta)
}
}
+ // todo: not always
return true;
}
@@ -161,8 +159,14 @@ private bool moveSelection(Vector2 delta)
return true;
}
+ ///
+ /// Returns a gamefield-space quad surrounding the current selection.
+ ///
private Quad getSelectionQuad()
{
+ if (!SelectedHitObjects.Any())
+ return new Quad();
+
Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue);
Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);
diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
index afaa5b0f3d..6cd503b580 100644
--- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs
@@ -43,6 +43,8 @@ public class SelectionHandler : CompositeDrawable, IKeyBindingHandler new ComposeSelectionBox();
+ public ComposeSelectionBox CreateSelectionBox()
+ => new ComposeSelectionBox
+ {
+ OperationStarted = OnDragOperationBegan,
+ OperationEnded = OnDragOperationEnded,
+
+ OnRotation = e => HandleRotation(e.Delta.X),
+ OnScaleX = (e, anchor) => HandleScaleX(e.Delta.X, anchor),
+ OnScaleY = (e, anchor) => HandleScaleY(e.Delta.Y, anchor),
+ };
+
+ ///
+ /// Fired when a drag operation ends from the selection box.
+ ///
+ protected virtual void OnDragOperationBegan()
+ {
+ ChangeHandler.BeginChange();
+ }
+
+ ///
+ /// Fired when a drag operation begins from the selection box.
+ ///
+ protected virtual void OnDragOperationEnded()
+ {
+ ChangeHandler.EndChange();
+ }
#region User Input Handling
@@ -108,7 +135,30 @@ private void load(OsuColour colours)
/// Whether any s could be moved.
/// Returning true will also propagate StartTime changes provided by the closest .
///
- public virtual bool HandleMovement(MoveSelectionEvent moveEvent) => true;
+ public virtual bool HandleMovement(MoveSelectionEvent moveEvent) => false;
+
+ ///
+ /// Handles the selected s being rotated.
+ ///
+ /// The delta angle to apply to the selection.
+ /// Whether any s could be moved.
+ public virtual bool HandleRotation(float angle) => false;
+
+ ///
+ /// Handles the selected s being scaled in a vertical direction.
+ ///
+ /// The delta scale to apply.
+ /// The point of reference where the scale is originating from.
+ /// Whether any s could be moved.
+ public virtual bool HandleScaleY(in float scale, Anchor anchor) => false;
+
+ ///
+ /// Handles the selected s being scaled in a horizontal direction.
+ ///
+ /// The delta scale to apply.
+ /// The point of reference where the scale is originating from.
+ /// Whether any s could be moved.
+ public virtual bool HandleScaleX(in float scale, Anchor anchor) => false;
public bool OnPressed(PlatformAction action)
{
@@ -211,11 +261,22 @@ internal void UpdateVisibility()
selectionDetailsText.Text = count > 0 ? count.ToString() : string.Empty;
if (count > 0)
+ {
Show();
+ OnSelectionChanged();
+ }
else
Hide();
}
+ ///
+ /// Triggered whenever more than one object is selected, on each change.
+ /// Should update the selection box's state to match supported operations.
+ ///
+ protected virtual void OnSelectionChanged()
+ {
+ }
+
protected override void Update()
{
base.Update();