// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osuTK; namespace osu.Game.Rulesets.Edit { /// /// A blueprint placed above a adding editing functionality. /// public abstract class SelectionBlueprint : CompositeDrawable, IStateful { /// /// Invoked when this has been selected. /// public event Action Selected; /// /// Invoked when this has been deselected. /// public event Action Deselected; /// /// The which this applies to. /// public readonly DrawableHitObject DrawableObject; protected override bool ShouldBeAlive => (DrawableObject.IsAlive && DrawableObject.IsPresent) || State == SelectionState.Selected; public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; [Resolved(CanBeNull = true)] private HitObjectComposer composer { get; set; } protected SelectionBlueprint(DrawableHitObject drawableObject) { DrawableObject = drawableObject; RelativeSizeAxes = Axes.Both; AlwaysPresent = true; Alpha = 0; } private SelectionState state; public event Action StateChanged; public SelectionState State { get => state; set { if (state == value) return; state = value; switch (state) { case SelectionState.Selected: Show(); Selected?.Invoke(this); break; case SelectionState.NotSelected: Hide(); Deselected?.Invoke(this); break; } StateChanged?.Invoke(state); } } // When not selected, input is only required for the blueprint itself to receive IsHovering protected override bool ShouldBeConsideredForInput(Drawable child) => State == SelectionState.Selected; /// /// Selects this , causing it to become visible. /// public void Select() => State = SelectionState.Selected; /// /// Deselects this , causing it to become invisible. /// public void Deselect() => State = SelectionState.NotSelected; public bool IsSelected => State == SelectionState.Selected; /// /// Updates the , invoking and re-processing the beatmap. /// protected void UpdateHitObject() => composer?.UpdateHitObject(DrawableObject.HitObject); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.ReceivePositionalInputAt(screenSpacePos); /// /// The s to be displayed in the context menu for this . /// public virtual MenuItem[] ContextMenuItems => Array.Empty(); /// /// The screen-space point that causes this to be selected. /// public virtual Vector2 SelectionPoint => DrawableObject.ScreenSpaceDrawQuad.Centre; /// /// The screen-space quad that outlines this for selections. /// public virtual Quad SelectionQuad => DrawableObject.ScreenSpaceDrawQuad; } }