Files
osukey/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.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

109 lines
3.8 KiB
C#

// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
public class HitObjectMaskLayer : CompositeDrawable
{
private readonly Playfield playfield;
private readonly HitObjectComposer composer;
private readonly Container<HitObjectMask> overlayContainer;
private readonly SelectionBox selectionBox;
private readonly HashSet<HitObjectMask> selectedObjects = new HashSet<HitObjectMask>();
public HitObjectMaskLayer(Playfield playfield, HitObjectComposer composer)
{
this.playfield = playfield;
this.composer = composer;
RelativeSizeAxes = Axes.Both;
overlayContainer = new Container<HitObjectMask>();
selectionBox = composer.CreateSelectionBox();
var dragBox = new DragBox(overlayContainer);
dragBox.DragEnd += () => selectionBox.FinishSelection();
InternalChildren = new Drawable[]
{
dragBox,
overlayContainer,
selectionBox,
dragBox.CreateProxy()
};
}
[BackgroundDependencyLoader]
private void load()
{
foreach (var obj in playfield.HitObjects.Objects)
addOverlay(obj);
}
/// <summary>
/// Adds an overlay for a <see cref="DrawableHitObject"/> which adds movement support.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to create an overlay for.</param>
private void addOverlay(DrawableHitObject hitObject)
{
var overlay = composer.CreateMaskFor(hitObject);
if (overlay == null)
return;
overlay.Selected += onSelected;
overlay.Deselected += onDeselected;
overlay.SingleSelectionRequested += onSingleSelectionRequested;
overlayContainer.Add(overlay);
selectionBox.AddMask(overlay);
}
/// <summary>
/// Removes the overlay for a <see cref="DrawableHitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableHitObject"/> to remove the overlay for.</param>
private void removeOverlay(DrawableHitObject hitObject)
{
var existing = overlayContainer.FirstOrDefault(h => h.HitObject == hitObject);
if (existing == null)
return;
existing.Selected -= onSelected;
existing.Deselected -= onDeselected;
existing.SingleSelectionRequested -= onSingleSelectionRequested;
overlayContainer.Remove(existing);
selectionBox.RemoveMask(existing);
}
private void onSelected(HitObjectMask mask) => selectedObjects.Add(mask);
private void onDeselected(HitObjectMask mask) => selectedObjects.Remove(mask);
private void onSingleSelectionRequested(HitObjectMask mask) => DeselectAll();
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
DeselectAll();
return true;
}
/// <summary>
/// Deselects all selected <see cref="DrawableHitObject"/>s.
/// </summary>
public void DeselectAll() => overlayContainer.ToList().ForEach(m => m.Deselect());
}
}