mirror of
https://github.com/osukey/osukey.git
synced 2025-07-02 16:59:53 +09:00
The general idea here is that we need the masks to handle mouse down events, as they need to handle the drag (mousedown -> drag immediately). I've rewritten the editor selections to use events, as there are some 3 different components that handle/trigger selections in different ways. 1. All selections/deselections now propagate through `HitObjectMask.Select()`/`HitObjectMask.Deselect()`. 2. Components that react to changes in the selection bind to the masks' `Selected`/`Deselected` events, and track them/change their states locally. 3. Masks provide a `SingleSelectionRequested` event which is invoked on the mouse-down event. Various components bind to this event to perform state changes locally in this scenario. 4. `DragBox` now handles all drag input locally. It triggers `Select`/`Deselect` on the masks it needs to. 5. `SelectionBox` handles the display of itself locally. 6. `SelectionBox` handles movement of groups of masks locally. 7. `HitObjectMasks` handles movement of itself locally.
98 lines
3.1 KiB
C#
98 lines
3.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using osu.Framework.Allocation;
|
|
using osu.Framework.Graphics;
|
|
using osu.Framework.Graphics.Containers;
|
|
using osu.Framework.Graphics.Primitives;
|
|
using osu.Framework.Graphics.Shapes;
|
|
using osu.Framework.Input;
|
|
using osu.Game.Rulesets.Edit;
|
|
using OpenTK.Graphics;
|
|
|
|
namespace osu.Game.Screens.Edit.Screens.Compose.Layers
|
|
{
|
|
/// <summary>
|
|
/// A box that represents a drag selection.
|
|
/// </summary>
|
|
public class DragBox : CompositeDrawable
|
|
{
|
|
public event Action DragEnd;
|
|
|
|
private readonly IEnumerable<HitObjectMask> hitObjectMasks;
|
|
|
|
private Drawable box;
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="DragBox"/>.
|
|
/// </summary>
|
|
/// <param name="hitObjectMasks">The selectable <see cref="HitObjectMask"/>s.</param>
|
|
public DragBox(IEnumerable<HitObjectMask> hitObjectMasks)
|
|
{
|
|
this.hitObjectMasks = hitObjectMasks;
|
|
|
|
RelativeSizeAxes = Axes.Both;
|
|
AlwaysPresent = true;
|
|
Alpha = 0;
|
|
}
|
|
|
|
[BackgroundDependencyLoader]
|
|
private void load()
|
|
{
|
|
InternalChild = box = new Container
|
|
{
|
|
Masking = true,
|
|
BorderColour = Color4.White,
|
|
BorderThickness = SelectionBox.BORDER_RADIUS,
|
|
Child = new Box
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Alpha = 0.1f
|
|
}
|
|
};
|
|
}
|
|
|
|
protected override bool OnDragStart(InputState state)
|
|
{
|
|
this.FadeIn(250, Easing.OutQuint);
|
|
return true;
|
|
}
|
|
|
|
protected override bool OnDrag(InputState state)
|
|
{
|
|
var dragPosition = state.Mouse.NativeState.Position;
|
|
var dragStartPosition = state.Mouse.NativeState.PositionMouseDown ?? dragPosition;
|
|
|
|
var dragQuad = new Quad(dragStartPosition.X, dragStartPosition.Y, dragPosition.X - dragStartPosition.X, dragPosition.Y - dragStartPosition.Y);
|
|
|
|
// We use AABBFloat instead of RectangleF since it handles negative sizes for us
|
|
SetDragRectangle(dragQuad.AABBFloat);
|
|
|
|
return true;
|
|
}
|
|
|
|
protected override bool OnDragEnd(InputState state)
|
|
{
|
|
this.FadeOut(250, Easing.OutQuint);
|
|
DragEnd?.Invoke();
|
|
return true;
|
|
}
|
|
|
|
public void SetDragRectangle(RectangleF screenSpaceRectangle)
|
|
{
|
|
var topLeft = ToLocalSpace(screenSpaceRectangle.TopLeft);
|
|
var bottomRight = ToLocalSpace(screenSpaceRectangle.BottomRight);
|
|
|
|
box.Position = topLeft;
|
|
box.Size = bottomRight - topLeft;
|
|
|
|
foreach (var mask in hitObjectMasks)
|
|
{
|
|
if (mask.IsAlive && mask.IsPresent && screenSpaceRectangle.Contains(mask.SelectionPoint))
|
|
mask.Select();
|
|
else
|
|
mask.Deselect();
|
|
}
|
|
}
|
|
}
|
|
}
|