2019-01-24 08:43:03 +00:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-10-29 05:07:06 +00:00
2019-10-24 10:02:59 +00:00
using System ;
2018-10-29 05:07:06 +00:00
using osu.Framework.Allocation ;
2019-10-31 07:23:54 +00:00
using osu.Framework.Bindables ;
2020-04-13 12:59:23 +00:00
using osu.Framework.Extensions.Color4Extensions ;
2018-10-29 05:07:06 +00:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
using osu.Framework.Graphics.Shapes ;
using osu.Framework.Input.Events ;
using osu.Game.Graphics ;
2019-11-07 05:00:12 +00:00
using osu.Game.Rulesets.Edit ;
2019-12-09 11:49:59 +00:00
using osu.Game.Rulesets.Objects ;
2018-10-29 05:07:06 +00:00
using osu.Game.Rulesets.Osu.Objects ;
2020-04-09 13:00:56 +00:00
using osu.Game.Screens.Edit ;
2018-11-20 07:51:59 +00:00
using osuTK ;
2019-10-31 07:23:54 +00:00
using osuTK.Graphics ;
2019-11-12 09:35:28 +00:00
using osuTK.Input ;
2018-10-29 05:07:06 +00:00
2018-11-07 07:08:56 +00:00
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
2018-10-29 05:07:06 +00:00
{
2019-12-11 11:14:16 +00:00
/// <summary>
/// A visualisation of a single <see cref="PathControlPoint"/> in a <see cref="Slider"/>.
/// </summary>
2019-09-27 09:45:22 +00:00
public class PathControlPointPiece : BlueprintPiece < Slider >
2018-10-29 05:07:06 +00:00
{
2019-12-09 11:49:59 +00:00
public Action < PathControlPointPiece , MouseButtonEvent > RequestSelection ;
2019-10-24 10:02:59 +00:00
2019-11-03 09:41:29 +00:00
public readonly BindableBool IsSelected = new BindableBool ( ) ;
2019-12-09 11:49:59 +00:00
public readonly PathControlPoint ControlPoint ;
2018-10-29 05:07:06 +00:00
2019-10-31 07:23:54 +00:00
private readonly Slider slider ;
private readonly Container marker ;
private readonly Drawable markerRing ;
2018-10-29 05:07:06 +00:00
2020-04-09 13:00:56 +00:00
[Resolved(CanBeNull = true)]
private IEditorChangeHandler changeHandler { get ; set ; }
2019-11-07 05:00:12 +00:00
[Resolved(CanBeNull = true)]
2020-05-20 08:48:43 +00:00
private IPositionSnapProvider snapProvider { get ; set ; }
2019-11-07 05:00:12 +00:00
2018-10-29 05:07:06 +00:00
[Resolved]
private OsuColour colours { get ; set ; }
2019-12-09 11:49:59 +00:00
private IBindable < Vector2 > sliderPosition ;
2019-12-10 02:20:08 +00:00
private IBindable < Vector2 > controlPointPosition ;
2019-12-09 11:49:59 +00:00
public PathControlPointPiece ( Slider slider , PathControlPoint controlPoint )
2018-10-29 05:07:06 +00:00
{
this . slider = slider ;
2019-12-09 11:49:59 +00:00
ControlPoint = controlPoint ;
2018-10-29 05:07:06 +00:00
2020-04-13 12:59:23 +00:00
controlPoint . Type . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2018-10-29 05:07:06 +00:00
Origin = Anchor . Centre ;
2018-10-29 07:15:04 +00:00
AutoSizeAxes = Axes . Both ;
2018-10-29 05:07:06 +00:00
InternalChildren = new Drawable [ ]
{
2019-10-31 07:23:54 +00:00
marker = new Container
2018-10-29 05:07:06 +00:00
{
2018-10-29 07:15:04 +00:00
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2019-10-31 07:23:54 +00:00
AutoSizeAxes = Axes . Both ,
Children = new [ ]
{
new Circle
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
Size = new Vector2 ( 10 ) ,
} ,
markerRing = new CircularContainer
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
Size = new Vector2 ( 14 ) ,
Masking = true ,
BorderThickness = 2 ,
BorderColour = Color4 . White ,
Alpha = 0 ,
Child = new Box
{
RelativeSizeAxes = Axes . Both ,
Alpha = 0 ,
AlwaysPresent = true
}
}
}
2018-10-29 05:07:06 +00:00
}
} ;
}
2019-12-09 11:49:59 +00:00
protected override void LoadComplete ( )
2018-10-29 05:07:06 +00:00
{
2019-12-09 11:49:59 +00:00
base . LoadComplete ( ) ;
2018-10-29 05:07:06 +00:00
2019-12-09 11:49:59 +00:00
sliderPosition = slider . PositionBindable . GetBoundCopy ( ) ;
2019-12-10 02:20:08 +00:00
sliderPosition . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2019-10-31 07:23:54 +00:00
2019-12-10 02:20:08 +00:00
controlPointPosition = ControlPoint . Position . GetBoundCopy ( ) ;
controlPointPosition . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2019-10-31 07:23:54 +00:00
2019-12-09 11:49:59 +00:00
IsSelected . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2018-10-29 05:07:06 +00:00
2019-12-09 11:49:59 +00:00
updateMarkerDisplay ( ) ;
2018-10-29 05:07:06 +00:00
}
2019-10-31 07:23:54 +00:00
// The connecting path is excluded from positional input
2018-10-29 07:15:04 +00:00
public override bool ReceivePositionalInputAt ( Vector2 screenSpacePos ) = > marker . ReceivePositionalInputAt ( screenSpacePos ) ;
2019-12-09 11:49:59 +00:00
protected override bool OnHover ( HoverEvent e )
{
updateMarkerDisplay ( ) ;
2019-12-09 15:08:38 +00:00
return false ;
2019-12-09 11:49:59 +00:00
}
protected override void OnHoverLost ( HoverLostEvent e )
{
updateMarkerDisplay ( ) ;
}
2019-10-31 08:13:10 +00:00
protected override bool OnMouseDown ( MouseDownEvent e )
{
2019-11-13 08:28:18 +00:00
if ( RequestSelection = = null )
2019-11-12 09:35:28 +00:00
return false ;
2019-11-13 08:28:18 +00:00
switch ( e . Button )
2019-11-03 10:59:37 +00:00
{
2019-11-13 08:28:18 +00:00
case MouseButton . Left :
2019-12-09 11:49:59 +00:00
RequestSelection . Invoke ( this , e ) ;
2019-11-13 08:28:18 +00:00
return true ;
case MouseButton . Right :
if ( ! IsSelected . Value )
2019-12-09 11:49:59 +00:00
RequestSelection . Invoke ( this , e ) ;
2019-11-13 08:28:18 +00:00
return false ; // Allow context menu to show
2019-11-03 10:59:37 +00:00
}
return false ;
2019-10-31 08:13:10 +00:00
}
2019-11-13 08:28:18 +00:00
protected override bool OnClick ( ClickEvent e ) = > RequestSelection ! = null ;
2019-11-04 17:21:50 +00:00
2020-04-09 13:00:56 +00:00
protected override bool OnDragStart ( DragStartEvent e )
{
2020-04-23 03:17:11 +00:00
if ( RequestSelection = = null )
return false ;
2020-04-09 13:00:56 +00:00
if ( e . Button = = MouseButton . Left )
{
changeHandler ? . BeginChange ( ) ;
return true ;
}
return false ;
}
2018-10-29 05:07:06 +00:00
2020-01-20 09:17:21 +00:00
protected override void OnDrag ( DragEvent e )
2018-10-29 05:07:06 +00:00
{
2019-12-09 11:49:59 +00:00
if ( ControlPoint = = slider . Path . ControlPoints [ 0 ] )
2018-10-29 06:36:43 +00:00
{
2019-11-07 05:00:12 +00:00
// Special handling for the head control point - the position of the slider changes which means the snapped position and time have to be taken into account
2020-05-22 09:57:28 +00:00
var result = snapProvider ? . SnapScreenSpacePositionToValidTime ( e . ScreenSpaceMousePosition ) ;
Vector2 movementDelta = Parent . ToLocalSpace ( result ? . ScreenSpacePosition ? ? e . ScreenSpaceMousePosition ) - slider . Position ;
2019-11-07 05:00:12 +00:00
slider . Position + = movementDelta ;
2020-05-20 09:19:21 +00:00
slider . StartTime = result ? . Time ? ? slider . StartTime ;
2018-10-29 06:36:43 +00:00
// Since control points are relative to the position of the slider, they all need to be offset backwards by the delta
2019-12-05 10:53:31 +00:00
for ( int i = 1 ; i < slider . Path . ControlPoints . Count ; i + + )
slider . Path . ControlPoints [ i ] . Position . Value - = movementDelta ;
2018-10-29 06:36:43 +00:00
}
else
2019-12-09 11:49:59 +00:00
ControlPoint . Position . Value + = e . Delta ;
2018-10-29 05:07:06 +00:00
}
2020-04-09 13:00:56 +00:00
protected override void OnDragEnd ( DragEndEvent e ) = > changeHandler ? . EndChange ( ) ;
2019-12-09 11:49:59 +00:00
/// <summary>
/// Updates the state of the circular control point marker.
/// </summary>
private void updateMarkerDisplay ( )
{
Position = slider . StackedPosition + ControlPoint . Position . Value ;
markerRing . Alpha = IsSelected . Value ? 1 : 0 ;
Color4 colour = ControlPoint . Type . Value ! = null ? colours . Red : colours . Yellow ;
2020-04-13 12:59:23 +00:00
2019-12-09 11:49:59 +00:00
if ( IsHovered | | IsSelected . Value )
2020-04-13 12:59:23 +00:00
colour = colour . Lighten ( 1 ) ;
2019-12-09 11:49:59 +00:00
marker . Colour = colour ;
}
2018-10-29 05:07:06 +00:00
}
}