Files
osukey/osu.Game/Screens/Edit/Screens/Compose/Layers/DragBox.cs
smoogipoo 6d4f94756e Rewrite the way drag + click selections happen
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.
2018-03-29 22:07:23 +09:00

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();
}
}
}
}