mirror of
https://github.com/ppy/osu
synced 2025-01-18 20:10:49 +00:00
Merge pull request #20703 from ekrctb/improve-drag-selection
Improve editor drag box selection logic
This commit is contained in:
commit
9ccfac7bd1
@ -15,6 +15,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -106,11 +107,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
protected virtual DragBox CreateDragBox() => new DragBox();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this component is in a state where items outside a drag selection should be deselected. If false, selection will only be added to.
|
||||
/// </summary>
|
||||
protected virtual bool AllowDeselectionDuringDrag => true;
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
bool selectionPerformed = performMouseDownActions(e);
|
||||
@ -174,11 +170,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
finishSelectionMovement();
|
||||
}
|
||||
|
||||
private MouseButtonEvent lastDragEvent;
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (e.Button == MouseButton.Right)
|
||||
return false;
|
||||
|
||||
lastDragEvent = e;
|
||||
|
||||
if (movementBlueprints != null)
|
||||
{
|
||||
isDraggingBlueprint = true;
|
||||
@ -193,22 +193,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
if (e.Button == MouseButton.Right)
|
||||
return;
|
||||
|
||||
if (DragBox.State == Visibility.Visible)
|
||||
{
|
||||
DragBox.HandleDrag(e);
|
||||
UpdateSelectionFromDragBox();
|
||||
}
|
||||
lastDragEvent = e;
|
||||
|
||||
moveCurrentSelection(e);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
if (e.Button == MouseButton.Right)
|
||||
return;
|
||||
lastDragEvent = null;
|
||||
|
||||
if (isDraggingBlueprint)
|
||||
{
|
||||
@ -219,6 +211,18 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
DragBox.Hide();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (lastDragEvent != null && DragBox.State == Visibility.Visible)
|
||||
{
|
||||
lastDragEvent.Target = this;
|
||||
DragBox.HandleDrag(lastDragEvent);
|
||||
UpdateSelectionFromDragBox();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever a drag operation completes, before any change transaction is committed.
|
||||
/// </summary>
|
||||
@ -389,12 +393,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
foreach (var blueprint in SelectionBlueprints)
|
||||
{
|
||||
if (blueprint.IsSelected && !AllowDeselectionDuringDrag)
|
||||
continue;
|
||||
switch (blueprint.State)
|
||||
{
|
||||
case SelectionState.Selected:
|
||||
// Selection is preserved even after blueprint becomes dead.
|
||||
if (!quad.Contains(blueprint.ScreenSpaceSelectionPoint))
|
||||
blueprint.Deselect();
|
||||
break;
|
||||
|
||||
bool shouldBeSelected = blueprint.IsAlive && blueprint.IsPresent && quad.Contains(blueprint.ScreenSpaceSelectionPoint);
|
||||
if (blueprint.IsSelected != shouldBeSelected)
|
||||
blueprint.ToggleSelection();
|
||||
case SelectionState.NotSelected:
|
||||
if (blueprint.IsAlive && blueprint.IsPresent && quad.Contains(blueprint.ScreenSpaceSelectionPoint))
|
||||
blueprint.Select();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -37,7 +36,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
protected new EditorSelectionHandler SelectionHandler => (EditorSelectionHandler)base.SelectionHandler;
|
||||
|
||||
private PlacementBlueprint currentPlacement;
|
||||
private InputManager inputManager;
|
||||
|
||||
/// <remarks>
|
||||
/// Positional input must be received outside the container's bounds,
|
||||
@ -66,8 +64,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
inputManager = GetContainingInputManager();
|
||||
|
||||
Beatmap.HitObjectAdded += hitObjectAdded;
|
||||
|
||||
// updates to selected are handled for us by SelectionHandler.
|
||||
@ -83,8 +79,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool AllowDeselectionDuringDrag => !EditorClock.IsRunning;
|
||||
|
||||
protected override void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject)
|
||||
{
|
||||
base.TransferBlueprintFor(hitObject, drawableObject);
|
||||
@ -222,7 +216,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
private void updatePlacementPosition()
|
||||
{
|
||||
var snapResult = Composer.FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position);
|
||||
var snapResult = Composer.FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position);
|
||||
|
||||
// if no time was found from positional snapping, we should still quantize to the beat.
|
||||
snapResult.Time ??= Beatmap.SnapTime(EditorClock.CurrentTime, null);
|
||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -27,6 +28,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
private HitObjectUsageEventBuffer usageEventBuffer;
|
||||
|
||||
protected InputManager InputManager { get; private set; }
|
||||
|
||||
protected EditorBlueprintContainer(HitObjectComposer composer)
|
||||
{
|
||||
Composer = composer;
|
||||
@ -42,6 +45,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
InputManager = GetContainingInputManager();
|
||||
|
||||
Beatmap.HitObjectAdded += AddBlueprintFor;
|
||||
Beatmap.HitObjectRemoved += RemoveBlueprintFor;
|
||||
|
||||
|
@ -29,10 +29,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
[Resolved(CanBeNull = true)]
|
||||
private Timeline timeline { get; set; }
|
||||
|
||||
private DragEvent lastDragEvent;
|
||||
private Bindable<HitObject> placement;
|
||||
private SelectionBlueprint<HitObject> placementBlueprint;
|
||||
|
||||
private bool hitObjectDragged;
|
||||
|
||||
/// <remarks>
|
||||
/// Positional input must be received outside the container's bounds,
|
||||
/// in order to handle timeline blueprints which are stacked offscreen.
|
||||
@ -98,24 +99,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
return base.OnDragStart(e);
|
||||
}
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
handleScrollViaDrag(e);
|
||||
|
||||
base.OnDrag(e);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
base.OnDragEnd(e);
|
||||
lastDragEvent = null;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
// trigger every frame so drags continue to update selection while playback is scrolling the timeline.
|
||||
if (lastDragEvent != null)
|
||||
OnDrag(lastDragEvent);
|
||||
if (IsDragged || hitObjectDragged)
|
||||
handleScrollViaDrag();
|
||||
|
||||
if (Composer != null && timeline != null)
|
||||
{
|
||||
@ -170,7 +157,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
return new TimelineHitObjectBlueprint(item)
|
||||
{
|
||||
OnDragHandled = handleScrollViaDrag,
|
||||
OnDragHandled = e => hitObjectDragged = e != null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -197,24 +184,18 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
}
|
||||
}
|
||||
|
||||
private void handleScrollViaDrag(DragEvent e)
|
||||
private void handleScrollViaDrag()
|
||||
{
|
||||
lastDragEvent = e;
|
||||
if (timeline == null) return;
|
||||
|
||||
if (lastDragEvent == null)
|
||||
return;
|
||||
var timelineQuad = timeline.ScreenSpaceDrawQuad;
|
||||
float mouseX = InputManager.CurrentState.Mouse.Position.X;
|
||||
|
||||
if (timeline != null)
|
||||
{
|
||||
var timelineQuad = timeline.ScreenSpaceDrawQuad;
|
||||
float mouseX = e.ScreenSpaceMousePosition.X;
|
||||
|
||||
// scroll if in a drag and dragging outside visible extents
|
||||
if (mouseX > timelineQuad.TopRight.X)
|
||||
timeline.ScrollBy((float)((mouseX - timelineQuad.TopRight.X) / 10 * Clock.ElapsedFrameTime));
|
||||
else if (mouseX < timelineQuad.TopLeft.X)
|
||||
timeline.ScrollBy((float)((mouseX - timelineQuad.TopLeft.X) / 10 * Clock.ElapsedFrameTime));
|
||||
}
|
||||
// scroll if in a drag and dragging outside visible extents
|
||||
if (mouseX > timelineQuad.TopRight.X)
|
||||
timeline.ScrollBy((float)((mouseX - timelineQuad.TopRight.X) / 10 * Clock.ElapsedFrameTime));
|
||||
else if (mouseX < timelineQuad.TopLeft.X)
|
||||
timeline.ScrollBy((float)((mouseX - timelineQuad.TopLeft.X) / 10 * Clock.ElapsedFrameTime));
|
||||
}
|
||||
|
||||
private class SelectableAreaBackground : CompositeDrawable
|
||||
|
Loading…
Reference in New Issue
Block a user