diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs index ec3e05dc3c..6392ffaca1 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/BlueprintContainer.cs @@ -1,19 +1,26 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // 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.Graphics.Primitives; using osu.Framework.Input.Events; +using osu.Framework.Input.States; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; namespace osu.Game.Screens.Edit.Screens.Compose.Layers { public class BlueprintContainer : CompositeDrawable { - private MaskContainer maskContainer; + private SelectionBlueprintContainer selectionBlueprints; + private MaskSelection maskSelection; + + private IEnumerable aliveMasks => selectionBlueprints.Children.Where(c => c.IsAlive); [Resolved] private HitObjectComposer composer { get; set; } @@ -26,25 +33,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers [BackgroundDependencyLoader] private void load() { - maskContainer = new MaskContainer(); + maskSelection = composer.CreateMaskSelection(); + maskSelection.DeselectAll = deselectAll; - var maskSelection = composer.CreateMaskSelection(); - - maskContainer.MaskSelected += maskSelection.HandleSelected; - maskContainer.MaskDeselected += maskSelection.HandleDeselected; - maskContainer.MaskSelectionRequested += maskSelection.HandleSelectionRequested; - maskContainer.MaskDragRequested += maskSelection.HandleDrag; - - maskSelection.DeselectAll = maskContainer.DeselectAll; - - var dragBox = new DragBox(maskContainer.Select); + var dragBox = new DragBox(select); dragBox.DragEnd += () => maskSelection.UpdateVisibility(); InternalChildren = new[] { dragBox, maskSelection, - maskContainer, + selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }, dragBox.CreateProxy() }; @@ -54,7 +53,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers protected override bool OnClick(ClickEvent e) { - maskContainer.DeselectAll(); + deselectAll(); return true; } @@ -68,7 +67,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers if (mask == null) return; - maskContainer.Add(mask); + mask.Selected += onMaskSelected; + mask.Deselected += onMaskDeselected; + mask.SelectionRequested += onSelectionRequested; + mask.DragRequested += onDragRequested; + + selectionBlueprints.Add(mask); } /// @@ -77,12 +81,76 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers /// The for which to remove the mask. public void RemoveMaskFor(DrawableHitObject hitObject) { - var maskToRemove = maskContainer.Single(m => m.HitObject == hitObject); + var maskToRemove = selectionBlueprints.Single(m => m.HitObject == hitObject); if (maskToRemove == null) return; maskToRemove.Deselect(); - maskContainer.Remove(maskToRemove); + + maskToRemove.Selected -= onMaskSelected; + maskToRemove.Deselected -= onMaskDeselected; + maskToRemove.SelectionRequested -= onSelectionRequested; + maskToRemove.DragRequested -= onDragRequested; + + selectionBlueprints.Remove(maskToRemove); + } + + /// + /// Select all masks in a given rectangle selection area. + /// + /// The rectangle to perform a selection on in screen-space coordinates. + private void select(RectangleF rect) + { + foreach (var mask in aliveMasks.ToList()) + { + if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) + mask.Select(); + else + mask.Deselect(); + } + } + + /// + /// Deselects all selected s. + /// + private void deselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); + + private void onMaskSelected(SelectionMask mask) + { + maskSelection.HandleSelected(mask); + selectionBlueprints.ChangeChildDepth(mask, 1); + } + + private void onMaskDeselected(SelectionMask mask) + { + maskSelection.HandleDeselected(mask); + selectionBlueprints.ChangeChildDepth(mask, 0); + } + + private void onSelectionRequested(SelectionMask mask, InputState state) => maskSelection.HandleSelectionRequested(mask, state); + + private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => maskSelection.HandleDrag(mask, delta, state); + + private class SelectionBlueprintContainer : Container + { + protected override int Compare(Drawable x, Drawable y) + { + if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) + return base.Compare(x, y); + return Compare(xMask, yMask); + } + + public int Compare(SelectionMask x, SelectionMask y) + { + // dpeth is used to denote selected status (we always want selected masks to handle input first). + int d = x.Depth.CompareTo(y.Depth); + if (d != 0) + return d; + + // Put earlier hitobjects towards the end of the list, so they handle input first + int i = y.HitObject.HitObject.StartTime.CompareTo(x.HitObject.HitObject.StartTime); + return i == 0 ? CompareReverseChildID(x, y) : i; + } } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs deleted file mode 100644 index 42a7757721..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.States; -using osu.Game.Rulesets.Edit; -using OpenTK; -using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class MaskContainer : Container - { - /// - /// Invoked when any is selected. - /// - public event Action MaskSelected; - - /// - /// Invoked when any is deselected. - /// - public event Action MaskDeselected; - - /// - /// Invoked when any requests selection. - /// - public event Action MaskSelectionRequested; - - /// - /// Invoked when any requests drag. - /// - public event Action MaskDragRequested; - - private IEnumerable aliveMasks => AliveInternalChildren.Cast(); - - public MaskContainer() - { - RelativeSizeAxes = Axes.Both; - } - - public override void Add(SelectionMask drawable) - { - if (drawable == null) throw new ArgumentNullException(nameof(drawable)); - - base.Add(drawable); - - drawable.Selected += onMaskSelected; - drawable.Deselected += onMaskDeselected; - drawable.SelectionRequested += onSelectionRequested; - drawable.DragRequested += onDragRequested; - } - - public override bool Remove(SelectionMask drawable) - { - if (drawable == null) throw new ArgumentNullException(nameof(drawable)); - - var result = base.Remove(drawable); - - if (result) - { - drawable.Selected -= onMaskSelected; - drawable.Deselected -= onMaskDeselected; - drawable.SelectionRequested -= onSelectionRequested; - drawable.DragRequested -= onDragRequested; - } - - return result; - } - - /// - /// Select all masks in a given rectangle selection area. - /// - /// The rectangle to perform a selection on in screen-space coordinates. - public void Select(RectangleF rect) - { - foreach (var mask in aliveMasks.ToList()) - { - if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) - mask.Select(); - else - mask.Deselect(); - } - } - - /// - /// Deselects all selected s. - /// - public void DeselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); - - private void onMaskSelected(SelectionMask mask) - { - MaskSelected?.Invoke(mask); - ChangeChildDepth(mask, 1); - } - - private void onMaskDeselected(SelectionMask mask) - { - MaskDeselected?.Invoke(mask); - ChangeChildDepth(mask, 0); - } - - private void onSelectionRequested(SelectionMask mask, InputState state) => MaskSelectionRequested?.Invoke(mask, state); - private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => MaskDragRequested?.Invoke(mask, delta, state); - - protected override int Compare(Drawable x, Drawable y) - { - if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) - return base.Compare(x, y); - return Compare(xMask, yMask); - } - - public int Compare(SelectionMask x, SelectionMask y) - { - // dpeth is used to denote selected status (we always want selected masks to handle input first). - int d = x.Depth.CompareTo(y.Depth); - if (d != 0) - return d; - - // Put earlier hitobjects towards the end of the list, so they handle input first - int i = y.HitObject.HitObject.StartTime.CompareTo(x.HitObject.HitObject.StartTime); - return i == 0 ? CompareReverseChildID(x, y) : i; - } - } -}