// 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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using OpenTK; namespace osu.Game.Rulesets.Edit.Layers.Selection { public class SelectionLayer : CompositeDrawable { private readonly Playfield playfield; public SelectionLayer(Playfield playfield) { this.playfield = playfield; RelativeSizeAxes = Axes.Both; } private SelectionBox selectionBox; private CaptureBox captureBox; private readonly List selectedHitObjects = new List(); protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { clearSelection(); return true; } protected override bool OnDragStart(InputState state) { AddInternal(selectionBox = new SelectionBox()); return true; } protected override bool OnDrag(InputState state) { var dragPosition = state.Mouse.NativeState.Position; var dragStartPosition = state.Mouse.NativeState.PositionMouseDown ?? dragPosition; var screenSpaceDragQuad = new Quad(dragStartPosition.X, dragStartPosition.Y, dragPosition.X - dragStartPosition.X, dragPosition.Y - dragStartPosition.Y); selectionBox.SetDragRectangle(screenSpaceDragQuad.AABBFloat); captureQuad(screenSpaceDragQuad); return true; } protected override bool OnDragEnd(InputState state) { selectionBox.Hide(); finishCapture(true); return true; } protected override bool OnClick(InputState state) { capturePoint(state.Mouse.NativeState.Position); finishCapture(false); return true; } /// /// Deselects all selected s. /// private void clearSelection() { selectedHitObjects.Clear(); captureBox?.Hide(); } /// /// Captures all hitobjects that are present within the area of a . /// /// The capture . private void captureQuad(Quad screenSpaceQuad) { foreach (var obj in playfield.HitObjects.Objects.Where(h => h.IsAlive && h.IsPresent && screenSpaceQuad.Contains(h.SelectionPoint))) selectedHitObjects.Add(obj); } /// /// Captures the top-most hitobject that is present under a specific point. /// /// The to capture at. private void capturePoint(Vector2 screenSpacePoint) { var captured = playfield.HitObjects.Objects.Reverse().Where(h => h.IsAlive && h.IsPresent).FirstOrDefault(h => h.ReceiveMouseInputAt(screenSpacePoint)); if (captured == null) return; selectedHitObjects.Add(captured); } private void finishCapture(bool fromDrag) { if (selectedHitObjects.Count == 0) return; // Due to https://github.com/ppy/osu-framework/issues/1382, we may get here through both // OnDragEnd and OnClick methods within a single frame, OnMouseDown doesn't help us here captureBox?.Hide(); if (fromDrag) AddInternal(captureBox = new DragCaptureBox(this, selectedHitObjects.ToList(), selectionBox.Position, selectionBox.Size)); else AddInternal(captureBox = new InstantCaptureBox(this, selectedHitObjects.ToList())); } } }