2019-01-24 17:43:03 +09: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 14:07:06 +09:00
2019-10-24 19:02:59 +09:00
using System ;
2018-10-29 14:07:06 +09:00
using osu.Framework.Allocation ;
2019-10-31 16:23:54 +09:00
using osu.Framework.Bindables ;
2018-10-29 14:07:06 +09:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
using osu.Framework.Graphics.Lines ;
using osu.Framework.Graphics.Shapes ;
using osu.Framework.Input.Events ;
using osu.Game.Graphics ;
2019-11-07 14:00:12 +09:00
using osu.Game.Rulesets.Edit ;
2019-12-09 20:49:59 +09:00
using osu.Game.Rulesets.Objects ;
2018-10-29 14:07:06 +09:00
using osu.Game.Rulesets.Osu.Objects ;
2018-11-20 16:51:59 +09:00
using osuTK ;
2019-10-31 16:23:54 +09:00
using osuTK.Graphics ;
2019-11-12 18:35:28 +09:00
using osuTK.Input ;
2018-10-29 14:07:06 +09:00
2018-11-07 16:08:56 +09:00
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
2018-10-29 14:07:06 +09:00
{
2019-09-27 18:45:22 +09:00
public class PathControlPointPiece : BlueprintPiece < Slider >
2018-10-29 14:07:06 +09:00
{
2019-12-09 20:49:59 +09:00
public Action < PathControlPointPiece , MouseButtonEvent > RequestSelection ;
2019-10-24 19:02:59 +09:00
2019-11-03 18:41:29 +09:00
public readonly BindableBool IsSelected = new BindableBool ( ) ;
2019-12-09 20:49:59 +09:00
public readonly PathControlPoint ControlPoint ;
2018-10-29 14:07:06 +09:00
2019-10-31 16:23:54 +09:00
private readonly Slider slider ;
2018-10-29 14:07:06 +09:00
private readonly Path path ;
2019-10-31 16:23:54 +09:00
private readonly Container marker ;
private readonly Drawable markerRing ;
2018-10-29 14:07:06 +09:00
2019-11-07 14:00:12 +09:00
[Resolved(CanBeNull = true)]
private IDistanceSnapProvider snapProvider { get ; set ; }
2018-10-29 14:07:06 +09:00
[Resolved]
private OsuColour colours { get ; set ; }
2019-12-09 20:49:59 +09:00
private IBindable < Vector2 > sliderPosition ;
private IBindable < int > pathVersion ;
public PathControlPointPiece ( Slider slider , PathControlPoint controlPoint )
2018-10-29 14:07:06 +09:00
{
this . slider = slider ;
2019-12-09 20:49:59 +09:00
ControlPoint = controlPoint ;
2018-10-29 14:07:06 +09:00
Origin = Anchor . Centre ;
2018-10-29 16:15:04 +09:00
AutoSizeAxes = Axes . Both ;
2018-10-29 14:07:06 +09:00
InternalChildren = new Drawable [ ]
{
path = new SmoothPath
{
Anchor = Anchor . Centre ,
2019-03-07 17:39:19 +09:00
PathRadius = 1
2018-10-29 14:07:06 +09:00
} ,
2019-10-31 16:23:54 +09:00
marker = new Container
2018-10-29 14:07:06 +09:00
{
2018-10-29 16:15:04 +09:00
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2019-10-31 16:23:54 +09: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 14:07:06 +09:00
}
} ;
}
2019-12-09 20:49:59 +09:00
protected override void LoadComplete ( )
2018-10-29 14:07:06 +09:00
{
2019-12-09 20:49:59 +09:00
base . LoadComplete ( ) ;
2018-10-29 14:07:06 +09:00
2019-12-09 20:49:59 +09:00
sliderPosition = slider . PositionBindable . GetBoundCopy ( ) ;
sliderPosition . BindValueChanged ( _ = > updateDisplay ( ) ) ;
2019-10-31 16:23:54 +09:00
2019-12-09 20:49:59 +09:00
pathVersion = slider . Path . Version . GetBoundCopy ( ) ;
pathVersion . BindValueChanged ( _ = > updateDisplay ( ) ) ;
2019-10-31 16:23:54 +09:00
2019-12-09 20:49:59 +09:00
IsSelected . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2018-10-29 14:07:06 +09:00
2019-12-09 20:49:59 +09:00
updateDisplay ( ) ;
2019-10-31 16:23:54 +09:00
}
2018-10-29 14:07:06 +09:00
2019-12-09 20:49:59 +09:00
private void updateDisplay ( )
2019-10-31 16:23:54 +09:00
{
2019-12-09 20:49:59 +09:00
updateMarkerDisplay ( ) ;
updateConnectingPath ( ) ;
2018-10-29 14:07:06 +09:00
}
2019-10-31 16:23:54 +09:00
// The connecting path is excluded from positional input
2018-10-29 16:15:04 +09:00
public override bool ReceivePositionalInputAt ( Vector2 screenSpacePos ) = > marker . ReceivePositionalInputAt ( screenSpacePos ) ;
2019-12-09 20:49:59 +09:00
protected override bool OnHover ( HoverEvent e )
{
updateMarkerDisplay ( ) ;
2019-12-10 00:08:38 +09:00
return false ;
2019-12-09 20:49:59 +09:00
}
protected override void OnHoverLost ( HoverLostEvent e )
{
updateMarkerDisplay ( ) ;
}
2019-10-31 17:13:10 +09:00
protected override bool OnMouseDown ( MouseDownEvent e )
{
2019-11-13 17:28:18 +09:00
if ( RequestSelection = = null )
2019-11-12 18:35:28 +09:00
return false ;
2019-11-13 17:28:18 +09:00
switch ( e . Button )
2019-11-03 19:59:37 +09:00
{
2019-11-13 17:28:18 +09:00
case MouseButton . Left :
2019-12-09 20:49:59 +09:00
RequestSelection . Invoke ( this , e ) ;
2019-11-13 17:28:18 +09:00
return true ;
case MouseButton . Right :
if ( ! IsSelected . Value )
2019-12-09 20:49:59 +09:00
RequestSelection . Invoke ( this , e ) ;
2019-11-13 17:28:18 +09:00
return false ; // Allow context menu to show
2019-11-03 19:59:37 +09:00
}
return false ;
2019-10-31 17:13:10 +09:00
}
2019-11-13 17:28:18 +09:00
protected override bool OnMouseUp ( MouseUpEvent e ) = > RequestSelection ! = null ;
2019-11-05 02:21:50 +09:00
2019-11-13 17:28:18 +09:00
protected override bool OnClick ( ClickEvent e ) = > RequestSelection ! = null ;
2019-11-05 02:21:50 +09:00
2019-11-12 18:35:28 +09:00
protected override bool OnDragStart ( DragStartEvent e ) = > e . Button = = MouseButton . Left ;
2018-10-29 14:07:06 +09:00
protected override bool OnDrag ( DragEvent e )
{
2019-12-09 20:49:59 +09:00
if ( ControlPoint = = slider . Path . ControlPoints [ 0 ] )
2018-10-29 15:36:43 +09:00
{
2019-11-07 14:00:12 +09: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
( Vector2 snappedPosition , double snappedTime ) = snapProvider ? . GetSnappedPosition ( e . MousePosition , slider . StartTime ) ? ? ( e . MousePosition , slider . StartTime ) ;
Vector2 movementDelta = snappedPosition - slider . Position ;
slider . Position + = movementDelta ;
slider . StartTime = snappedTime ;
2018-10-29 15:36:43 +09: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 19:53:31 +09:00
for ( int i = 1 ; i < slider . Path . ControlPoints . Count ; i + + )
slider . Path . ControlPoints [ i ] . Position . Value - = movementDelta ;
2018-10-29 15:36:43 +09:00
}
else
2019-12-09 20:49:59 +09:00
ControlPoint . Position . Value + = e . Delta ;
2018-10-29 14:07:06 +09:00
return true ;
}
protected override bool OnDragEnd ( DragEndEvent e ) = > true ;
2019-12-09 20:49:59 +09: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 ;
if ( IsHovered | | IsSelected . Value )
colour = Color4 . White ;
marker . Colour = colour ;
}
/// <summary>
/// Updates the path connecting this control point to the previous one.
/// </summary>
private void updateConnectingPath ( )
{
path . ClearVertices ( ) ;
int index = slider . Path . ControlPoints . IndexOf ( ControlPoint ) ;
if ( index = = - 1 )
return ;
if ( + + index ! = slider . Path . ControlPoints . Count )
{
path . AddVertex ( Vector2 . Zero ) ;
path . AddVertex ( slider . Path . ControlPoints [ index ] . Position . Value - ControlPoint . Position . Value ) ;
}
path . OriginPosition = path . PositionInBoundingBox ( Vector2 . Zero ) ;
}
2018-10-29 14:07:06 +09:00
}
}