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