diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index f6354bc612..13dc7886ed 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -18,6 +18,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; +using osuTK; using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components @@ -105,7 +106,7 @@ public bool OnPressed(PlatformAction action) switch (action.ActionMethod) { case PlatformActionMethod.Delete: - return deleteSelected(); + return DeleteSelected(); } return false; @@ -115,6 +116,9 @@ public void OnReleased(PlatformAction action) { } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)); + private void selectPiece(PathControlPointPiece piece, MouseButtonEvent e) { if (e.Button == MouseButton.Left && inputManager.CurrentState.Keyboard.ControlPressed) @@ -126,7 +130,7 @@ private void selectPiece(PathControlPointPiece piece, MouseButtonEvent e) } } - private bool deleteSelected() + public bool DeleteSelected() { List toRemove = Pieces.Where(p => p.IsSelected.Value).Select(p => p.ControlPoint).ToList(); @@ -169,7 +173,7 @@ public MenuItem[] ContextMenuItems return new MenuItem[] { - new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => deleteSelected()), + new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => DeleteSelected()), new OsuMenuItem("Curve type") { Items = items diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index d3fb5defae..59b087f68f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -72,6 +73,18 @@ protected override void LoadComplete() BodyPiece.UpdateFrom(HitObject); } + public override bool HandleQuickDeletion() + { + var hoveredControlPoint = ControlPointVisualiser.Pieces.FirstOrDefault(p => p.IsHovered); + + if (hoveredControlPoint == null) + return false; + + hoveredControlPoint.IsSelected.Value = true; + ControlPointVisualiser.DeleteSelected(); + return true; + } + protected override void Update() { base.Update(); @@ -216,7 +229,8 @@ private void updatePath() public override Vector2 ScreenSpaceSelectionPoint => BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation); - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.ReceivePositionalInputAt(screenSpacePos) == true; protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position); } diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index f3816f6218..99cdca045b 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -143,5 +143,11 @@ protected virtual void OnSelected() public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; public virtual Vector2 GetInstantDelta(Vector2 screenSpacePosition) => Parent.ToLocalSpace(screenSpacePosition) - Position; + + /// + /// Handle to perform a partial deletion when the user requests a quick delete (Shift+Right Click). + /// + /// True if the deletion operation was handled by this blueprint. Returning false will delete the full blueprint. + public virtual bool HandleQuickDeletion() => false; } } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index fa98358dbe..d8f7137fa6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -116,7 +116,8 @@ protected virtual Container CreateSelectionBlueprintContaine protected override bool OnMouseDown(MouseDownEvent e) { - beginClickSelection(e); + if (beginClickSelection(e)) return true; + prepareSelectionMovement(); return e.Button == MouseButton.Left; @@ -291,19 +292,23 @@ protected virtual void AddBlueprintFor(HitObject hitObject) /// Attempts to select any hovered blueprints. /// /// The input event that triggered this selection. - private void beginClickSelection(MouseButtonEvent e) + private bool beginClickSelection(MouseButtonEvent e) { Debug.Assert(!clickSelectionBegan); + bool rightClickHandled = false; + foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren) { if (blueprint.IsHovered) { - SelectionHandler.HandleSelectionRequested(blueprint, e.CurrentState); + rightClickHandled |= SelectionHandler.HandleSelectionRequested(blueprint, e.CurrentState); clickSelectionBegan = true; break; } } + + return rightClickHandled; } /// diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index c2441b31a9..5bf6c52e11 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -219,18 +219,28 @@ internal void HandleDeselected(SelectionBlueprint blueprint) /// /// The blueprint. /// The input state at the point of selection. - internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) + /// Whether right click was handled. + internal bool HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right)) + { handleQuickDeletion(blueprint); - else if (state.Keyboard.ControlPressed && state.Mouse.IsPressed(MouseButton.Left)) + return true; + } + + if (state.Keyboard.ControlPressed && state.Mouse.IsPressed(MouseButton.Left)) blueprint.ToggleSelection(); else ensureSelected(blueprint); + + return false; } private void handleQuickDeletion(SelectionBlueprint blueprint) { + if (blueprint.HandleQuickDeletion()) + return; + if (!blueprint.IsSelected) EditorBeatmap.Remove(blueprint.HitObject); else