Move individual mask selection logic out of MaskSelection

This commit is contained in:
Dean Herbert 2018-04-04 18:21:27 +09:00
parent b6b8c51657
commit 4d71f2084c
7 changed files with 82 additions and 57 deletions

View File

@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(SelectionBox),
typeof(MaskSelection),
typeof(HitObjectComposer),
typeof(OsuHitObjectComposer),
typeof(HitObjectMaskLayer),

View File

@ -248,11 +248,11 @@ namespace osu.Game.Rulesets.Edit
public virtual HitObjectMask CreateMaskFor(DrawableHitObject hitObject) => null;
/// <summary>
/// Creates a <see cref="SelectionBox"/> which outlines <see cref="DrawableHitObject"/>s
/// Creates a <see cref="MaskSelection"/> which outlines <see cref="DrawableHitObject"/>s
/// and handles hitobject pattern adjustments.
/// </summary>
/// <param name="maskContainer">The <see cref="HitObjectMask"/> container.</param>
public virtual SelectionBox CreateSelectionBox(MaskContainer maskContainer) => new SelectionBox(maskContainer);
public virtual MaskSelection CreateSelectionBox(MaskContainer maskContainer) => new MaskSelection(maskContainer);
/// <summary>
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.

View File

@ -4,6 +4,7 @@
using System;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
@ -24,6 +25,13 @@ namespace osu.Game.Rulesets.Edit
/// </summary>
public event Action<HitObjectMask> Deselected;
/// <summary>
/// Invoked when this <see cref="HitObjectMask"/> has rqeuested selection.
/// Will fire even if already selected.
/// Does not actually perform selection.
/// </summary>
public event Action<HitObjectMask> SelectionRequested;
/// <summary>
/// The <see cref="DrawableHitObject"/> which this <see cref="HitObjectMask"/> applies to.
/// </summary>
@ -31,7 +39,8 @@ namespace osu.Game.Rulesets.Edit
protected override bool ShouldBeAlive => HitObject.IsAlive || State == Visibility.Visible;
public override bool RemoveWhenNotAlive => false;
public override bool HandleMouseInput => HitObject.IsPresent;
public override bool HandleMouseInput => ShouldBeAlive;
public HitObjectMask(DrawableHitObject hitObject)
{
@ -55,6 +64,12 @@ namespace osu.Game.Rulesets.Edit
return true;
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
SelectionRequested?.Invoke(this);
return base.OnMouseDown(state, args);
}
/// <summary>
/// Deselects this <see cref="HitObjectMask"/>, causing it to become invisible.
/// </summary>

View File

@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
Masking = true,
BorderColour = Color4.White,
BorderThickness = SelectionBox.BORDER_RADIUS,
BorderThickness = MaskSelection.BORDER_RADIUS,
Child = new Box
{
RelativeSizeAxes = Axes.Both,

View File

@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
private readonly HitObjectComposer composer;
private MaskContainer maskContainer;
private SelectionBox selectionBox;
private MaskSelection maskSelection;
public HitObjectMaskLayer(Playfield playfield, HitObjectComposer composer)
{
@ -33,16 +33,16 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
maskContainer = new MaskContainer();
selectionBox = composer.CreateSelectionBox(maskContainer);
maskSelection = composer.CreateSelectionBox(maskContainer);
dragLayer.DragEnd += () => selectionBox.UpdateVisibility();
var dragLayer = new DragLayer(maskContainer.Select);
dragLayer.DragEnd += () => maskSelection.UpdateVisibility();
InternalChildren = new Drawable[]
{
dragLayer,
maskSelection,
maskContainer,
selectionBox,
dragLayer.CreateProxy()
};
@ -50,6 +50,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
addMask(obj);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
maskContainer.DeselectAll();
return true;
}
/// <summary>
/// Adds a mask for a <see cref="DrawableHitObject"/> which adds movement support.
/// </summary>
@ -75,11 +81,5 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
maskContainer.Remove(mask);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
selectionBox.DeselectAll();
return true;
}
}
}

View File

@ -23,17 +23,25 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
/// </summary>
public event Action<HitObjectMask> MaskDeselected;
public event Action<HitObjectMask> MaskSelectionRequested;
/// <summary>
/// All the <see cref="HitObjectMask"/>s with <see cref="IsAlive"/> == true.
/// </summary>
public IEnumerable<HitObjectMask> AliveMasks => AliveInternalChildren.Cast<HitObjectMask>();
public MaskContainer()
{
RelativeSizeAxes = Axes.Both;
}
public override void Add(HitObjectMask drawable)
{
base.Add(drawable);
drawable.Selected += onMaskSelected;
drawable.Deselected += onMaskDeselected;
drawable.SelectionRequested += onSelectionRequested;
}
public override bool Remove(HitObjectMask drawable)
@ -44,6 +52,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
drawable.Selected -= onMaskSelected;
drawable.Deselected -= onMaskDeselected;
drawable.SelectionRequested -= onSelectionRequested;
}
return result;
@ -59,13 +68,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
{
if (mask.IsPresent && rect.Contains(mask.SelectionPoint))
mask.Select();
else
mask.Deselect();
}
}
/// <summary>
/// Deselects all selected <see cref="HitObjectMask"/>s.
/// </summary>
public void DeselectAll() => AliveMasks.ToList().ForEach(m => m.Deselect());
private void onMaskSelected(HitObjectMask mask) => MaskSelected?.Invoke(mask);
private void onMaskDeselected(HitObjectMask mask) => MaskDeselected?.Invoke(mask);
private void onSelectionRequested(HitObjectMask mask) => MaskSelectionRequested?.Invoke(mask);
protected override int Compare(Drawable x, Drawable y)
{

View File

@ -1,7 +1,6 @@
// 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;
@ -19,19 +18,19 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
/// <summary>
/// A box which surrounds <see cref="HitObjectMask"/>s and provides interactive handles, context menus etc.
/// </summary>
public class SelectionBox : CompositeDrawable
public class MaskSelection : CompositeDrawable
{
public const float BORDER_RADIUS = 2;
private readonly MaskContainer maskContainer;
private readonly SortedList<HitObjectMask> selectedMasks;
private IEnumerable<HitObjectMask> selectableMasks => maskContainer.AliveMasks;
private Drawable outline;
public SelectionBox(MaskContainer maskContainer)
public MaskSelection(MaskContainer maskContainer)
{
// todo: remove this
this.maskContainer = maskContainer;
selectedMasks = new SortedList<HitObjectMask>(maskContainer.Compare);
@ -42,6 +41,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
maskContainer.MaskSelected += onSelected;
maskContainer.MaskDeselected += onDeselected;
maskContainer.MaskSelectionRequested += onSelectionRequested;
}
[BackgroundDependencyLoader]
@ -63,42 +63,23 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
#region User Input Handling
/// <summary>
/// Handle input on currently selectable or already selected masks.
/// Keep in mind that selectedMasks may contain masks for non-current objects, which we still want to handle input while selected.
/// </summary>
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => selectableMasks.Reverse().Concat(selectedMasks).Any(m => m.ReceiveMouseInputAt(screenSpacePos));
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => handleInput(state);
protected override bool OnDragStart(InputState state) => handleInput(state);
protected override bool OnDragEnd(InputState state) => true;
private bool handleInput(InputState state)
{
// If masks are overlapping, make sure we don't change the selection if the overlapped portion is pressed
if (selectedMasks.Any(m => m.ReceiveMouseInputAt(state.Mouse.NativeState.Position)))
return true;
DeselectAll();
selectableMasks.Reverse().First(m => m.ReceiveMouseInputAt(state.Mouse.NativeState.Position)).Select();
if (!selectedMasks.Any(m => m.ReceiveMouseInputAt(state.Mouse.NativeState.Position)))
return false;
UpdateVisibility();
return true;
}
protected override bool OnClick(InputState state)
{
// If there's only mask, this isn't going to change anything, so we can save on doing some processing here
if (selectedMasks.Count == 1)
return true;
var toSelect = selectedMasks.Reverse().First(m => m.ReceiveMouseInputAt(state.Mouse.NativeState.Position));
DeselectAll();
toSelect.Select();
UpdateVisibility();
return true;
}
protected override bool OnDragStart(InputState state) => true;
protected override bool OnDrag(InputState state)
{
// Todo: Various forms of snapping
@ -116,8 +97,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
return true;
}
protected override bool OnDragEnd(InputState state) => true;
#endregion
#region Selection Handling
@ -133,15 +112,32 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
UpdateVisibility();
}
/// <summary>
/// Deselects all selected <see cref="HitObjectMask"/>s.
/// </summary>
public void DeselectAll() => selectedMasks.ToList().ForEach(m => m.Deselect());
private void onSelectionRequested(HitObjectMask mask)
{
if (GetContainingInputManager().CurrentState.Keyboard.ControlPressed)
{
if (mask.State == Visibility.Visible)
// we don't want this deselection to affect input for this frame.
Schedule(() => mask.Deselect());
else
mask.Select();
}
else
{
if (mask.State == Visibility.Visible)
return;
maskContainer.DeselectAll();
mask.Select();
}
UpdateVisibility();
}
#endregion
/// <summary>
/// Updates whether this <see cref="SelectionBox"/> is visible.
/// Updates whether this <see cref="MaskSelection"/> is visible.
/// </summary>
internal void UpdateVisibility()
{
@ -183,6 +179,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
maskContainer.MaskSelected -= onSelected;
maskContainer.MaskDeselected -= onDeselected;
maskContainer.MaskSelectionRequested -= onSelectionRequested;
}
}
}