2020-01-20 23:53:59 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 16:43:03 +08:00
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2018-03-29 21:06:45 +08:00
using System ;
2023-01-23 13:13:46 +08:00
using System.Linq ;
2023-10-30 14:10:10 +08:00
using JetBrains.Annotations ;
2018-04-04 19:44:07 +08:00
using osu.Framework ;
2018-10-25 17:16:25 +08:00
using osu.Framework.Graphics ;
2018-02-20 17:01:45 +08:00
using osu.Framework.Graphics.Containers ;
2018-03-29 21:06:45 +08:00
using osu.Framework.Graphics.Primitives ;
2019-11-12 12:38:42 +08:00
using osu.Framework.Graphics.UserInterface ;
2018-05-11 09:48:07 +08:00
using osu.Game.Graphics.UserInterface ;
2018-11-20 15:51:59 +08:00
using osuTK ;
2018-04-13 17:19:50 +08:00
2018-03-14 14:18:21 +08:00
namespace osu.Game.Rulesets.Edit
2018-02-20 17:01:45 +08:00
{
2018-03-14 14:18:21 +08:00
/// <summary>
2021-04-27 17:33:47 +08:00
/// A blueprint placed above a displaying item adding editing functionality.
2018-03-14 14:18:21 +08:00
/// </summary>
2021-04-27 14:40:35 +08:00
public abstract partial class SelectionBlueprint < T > : CompositeDrawable , IStateful < SelectionState >
2018-02-20 17:01:45 +08:00
{
2021-04-27 14:40:35 +08:00
public readonly T Item ;
2020-01-20 23:53:59 +08:00
2018-03-29 21:27:14 +08:00
/// <summary>
2021-04-27 14:40:35 +08:00
/// Invoked when this <see cref="SelectionBlueprint{T}"/> has been selected.
2018-03-29 21:27:14 +08:00
/// </summary>
2021-04-27 14:40:35 +08:00
public event Action < SelectionBlueprint < T > > Selected ;
2018-04-13 17:19:50 +08:00
2018-03-29 21:27:14 +08:00
/// <summary>
2021-04-27 14:40:35 +08:00
/// Invoked when this <see cref="SelectionBlueprint{T}"/> has been deselected.
2018-03-29 21:27:14 +08:00
/// </summary>
2021-04-27 14:40:35 +08:00
public event Action < SelectionBlueprint < T > > Deselected ;
2018-04-13 17:19:50 +08:00
2023-07-25 17:13:35 +08:00
public override bool HandlePositionalInput = > IsSelectable ;
2018-04-04 18:51:56 +08:00
public override bool RemoveWhenNotAlive = > false ;
2018-04-13 17:19:50 +08:00
2021-04-27 14:40:35 +08:00
protected SelectionBlueprint ( T item )
2018-02-20 17:01:45 +08:00
{
2021-04-27 14:40:35 +08:00
Item = item ;
2020-01-24 16:51:24 +08:00
2018-10-25 17:16:25 +08:00
RelativeSizeAxes = Axes . Both ;
2020-01-24 16:51:24 +08:00
AlwaysPresent = true ;
2020-01-21 16:36:21 +08:00
}
2018-10-25 17:16:25 +08:00
2020-01-24 16:51:24 +08:00
protected override void LoadComplete ( )
2020-01-21 16:36:21 +08:00
{
2020-01-24 16:51:24 +08:00
base . LoadComplete ( ) ;
updateState ( ) ;
2018-04-04 19:44:07 +08:00
}
2018-04-13 17:19:50 +08:00
2018-04-04 19:44:07 +08:00
private SelectionState state ;
2018-04-13 17:19:50 +08:00
2023-10-30 14:10:10 +08:00
[CanBeNull]
2018-04-04 19:44:07 +08:00
public event Action < SelectionState > StateChanged ;
2018-04-13 17:19:50 +08:00
2018-04-04 19:44:07 +08:00
public SelectionState State
{
get = > state ;
set
{
2019-04-25 16:36:17 +08:00
if ( state = = value )
return ;
2018-04-13 17:19:50 +08:00
2018-04-04 19:44:07 +08:00
state = value ;
2019-04-01 11:16:05 +08:00
2020-01-24 16:51:24 +08:00
if ( IsLoaded )
updateState ( ) ;
2019-04-25 16:36:17 +08:00
StateChanged ? . Invoke ( state ) ;
2018-04-04 19:44:07 +08:00
}
2018-03-09 22:12:34 +08:00
}
2018-04-13 17:19:50 +08:00
2020-01-24 16:51:24 +08:00
private void updateState ( )
{
switch ( state )
{
case SelectionState . Selected :
OnSelected ( ) ;
Selected ? . Invoke ( this ) ;
break ;
case SelectionState . NotSelected :
OnDeselected ( ) ;
Deselected ? . Invoke ( this ) ;
break ;
}
}
2020-10-09 13:03:13 +08:00
protected virtual void OnDeselected ( )
{
2021-04-27 17:33:47 +08:00
// selection blueprints are AlwaysPresent while the related item is visible
2020-10-09 13:03:13 +08:00
// set the body piece's alpha directly to avoid arbitrarily rendering frame buffers etc. of children.
foreach ( var d in InternalChildren )
d . Hide ( ) ;
}
2020-01-21 13:21:00 +08:00
2020-10-09 13:03:13 +08:00
protected virtual void OnSelected ( )
{
foreach ( var d in InternalChildren )
d . Show ( ) ;
}
2020-01-21 13:21:00 +08:00
2019-11-05 10:33:37 +08:00
// When not selected, input is only required for the blueprint itself to receive IsHovering
protected override bool ShouldBeConsideredForInput ( Drawable child ) = > State = = SelectionState . Selected ;
2018-03-29 21:06:45 +08:00
/// <summary>
2021-05-18 12:11:58 +08:00
/// Selects this <see cref="SelectionBlueprint{T}"/>, causing it to become visible.
2018-03-29 21:06:45 +08:00
/// </summary>
2018-04-04 19:44:07 +08:00
public void Select ( ) = > State = SelectionState . Selected ;
2018-04-13 17:19:50 +08:00
2018-04-04 19:44:07 +08:00
/// <summary>
2021-05-13 18:53:32 +08:00
/// Deselects this <see cref="HitObjectSelectionBlueprint"/>, causing it to become invisible.
2018-04-04 19:44:07 +08:00
/// </summary>
public void Deselect ( ) = > State = SelectionState . NotSelected ;
2018-04-13 17:19:50 +08:00
2020-10-27 05:16:28 +08:00
/// <summary>
2021-05-13 18:53:32 +08:00
/// Toggles the selection state of this <see cref="HitObjectSelectionBlueprint"/>.
2020-10-27 05:16:28 +08:00
/// </summary>
public void ToggleSelection ( ) = > State = IsSelected ? SelectionState . NotSelected : SelectionState . Selected ;
2018-04-04 19:44:07 +08:00
public bool IsSelected = > State = = SelectionState . Selected ;
2018-04-13 17:19:50 +08:00
2019-11-12 12:38:42 +08:00
/// <summary>
2021-05-13 18:53:32 +08:00
/// The <see cref="MenuItem"/>s to be displayed in the context menu for this <see cref="HitObjectSelectionBlueprint"/>.
2019-11-12 12:38:42 +08:00
/// </summary>
public virtual MenuItem [ ] ContextMenuItems = > Array . Empty < MenuItem > ( ) ;
2023-07-25 17:13:35 +08:00
/// <summary>
/// Whether the <see cref="SelectionBlueprint{T}"/> can be currently selected via a click or a drag box.
/// </summary>
public virtual bool IsSelectable = > ShouldBeAlive & & IsPresent ;
2018-03-29 21:06:45 +08:00
/// <summary>
2023-01-19 04:34:23 +08:00
/// The screen-space main point that causes this <see cref="HitObjectSelectionBlueprint"/> to be selected via a drag.
2018-03-29 21:06:45 +08:00
/// </summary>
2020-05-20 16:48:43 +08:00
public virtual Vector2 ScreenSpaceSelectionPoint = > ScreenSpaceDrawQuad . Centre ;
2018-04-13 17:19:50 +08:00
2023-01-23 13:13:46 +08:00
/// <summary>
/// Any points that should be used for snapping purposes in addition to <see cref="ScreenSpaceSelectionPoint"/>. Exposed via <see cref="ScreenSpaceSnapPoints"/>.
/// </summary>
protected virtual Vector2 [ ] ScreenSpaceAdditionalNodes = > Array . Empty < Vector2 > ( ) ;
2023-01-11 04:20:09 +08:00
/// <summary>
2023-01-24 04:22:18 +08:00
/// The screen-space collection of base points on this <see cref="HitObjectSelectionBlueprint"/> that other objects can be snapped to.
2023-01-19 04:34:23 +08:00
/// The first element of this collection is <see cref="ScreenSpaceSelectionPoint"/>
2023-01-11 04:20:09 +08:00
/// </summary>
2023-01-23 13:13:46 +08:00
public Vector2 [ ] ScreenSpaceSnapPoints = > ScreenSpaceAdditionalNodes . Prepend ( ScreenSpaceSelectionPoint ) . ToArray ( ) ;
2023-01-11 04:20:09 +08:00
2018-03-29 21:06:45 +08:00
/// <summary>
2021-05-13 18:53:32 +08:00
/// The screen-space quad that outlines this <see cref="HitObjectSelectionBlueprint"/> for selections.
2018-03-29 21:06:45 +08:00
/// </summary>
2020-01-20 23:53:59 +08:00
public virtual Quad SelectionQuad = > ScreenSpaceDrawQuad ;
2020-01-21 16:36:21 +08:00
2020-11-03 19:45:48 +08:00
/// <summary>
/// Handle to perform a partial deletion when the user requests a quick delete (Shift+Right Click).
/// </summary>
/// <returns>True if the deletion operation was handled by this blueprint. Returning false will delete the full blueprint.</returns>
public virtual bool HandleQuickDeletion ( ) = > false ;
2018-02-20 17:01:45 +08:00
}
}