2019-01-24 16:43:03 +08: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 13:07:06 +08:00
2019-10-24 18:02:59 +08:00
using System ;
2018-10-29 13:07:06 +08:00
using osu.Framework.Allocation ;
2019-10-31 15:23:54 +08:00
using osu.Framework.Bindables ;
2020-04-13 20:59:23 +08:00
using osu.Framework.Extensions.Color4Extensions ;
2018-10-29 13:07:06 +08: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 13:00:12 +08:00
using osu.Game.Rulesets.Edit ;
2019-12-09 19:49:59 +08:00
using osu.Game.Rulesets.Objects ;
2018-10-29 13:07:06 +08:00
using osu.Game.Rulesets.Osu.Objects ;
2020-04-09 21:00:56 +08:00
using osu.Game.Screens.Edit ;
2018-11-20 15:51:59 +08:00
using osuTK ;
2019-10-31 15:23:54 +08:00
using osuTK.Graphics ;
2019-11-12 17:35:28 +08:00
using osuTK.Input ;
2018-10-29 13:07:06 +08:00
2018-11-07 15:08:56 +08:00
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
2018-10-29 13:07:06 +08:00
{
2019-12-11 19:14:16 +08:00
/// <summary>
/// A visualisation of a single <see cref="PathControlPoint"/> in a <see cref="Slider"/>.
/// </summary>
2019-09-27 17:45:22 +08:00
public class PathControlPointPiece : BlueprintPiece < Slider >
2018-10-29 13:07:06 +08:00
{
2019-12-09 19:49:59 +08:00
public Action < PathControlPointPiece , MouseButtonEvent > RequestSelection ;
2019-10-24 18:02:59 +08:00
2019-11-03 17:41:29 +08:00
public readonly BindableBool IsSelected = new BindableBool ( ) ;
2019-12-09 19:49:59 +08:00
public readonly PathControlPoint ControlPoint ;
2018-10-29 13:07:06 +08:00
2019-10-31 15:23:54 +08:00
private readonly Slider slider ;
private readonly Container marker ;
private readonly Drawable markerRing ;
2018-10-29 13:07:06 +08:00
2020-04-09 21:00:56 +08:00
[Resolved(CanBeNull = true)]
private IEditorChangeHandler changeHandler { get ; set ; }
2019-11-07 13:00:12 +08:00
[Resolved(CanBeNull = true)]
2020-05-20 16:48:43 +08:00
private IPositionSnapProvider snapProvider { get ; set ; }
2019-11-07 13:00:12 +08:00
2018-10-29 13:07:06 +08:00
[Resolved]
private OsuColour colours { get ; set ; }
2019-12-09 19:49:59 +08:00
private IBindable < Vector2 > sliderPosition ;
2020-12-01 13:17:36 +08:00
private IBindable < float > sliderScale ;
2019-12-10 10:20:08 +08:00
private IBindable < Vector2 > controlPointPosition ;
2019-12-09 19:49:59 +08:00
public PathControlPointPiece ( Slider slider , PathControlPoint controlPoint )
2018-10-29 13:07:06 +08:00
{
this . slider = slider ;
2019-12-09 19:49:59 +08:00
ControlPoint = controlPoint ;
2018-10-29 13:07:06 +08:00
2020-04-13 20:59:23 +08:00
controlPoint . Type . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2018-10-29 13:07:06 +08:00
Origin = Anchor . Centre ;
2018-10-29 15:15:04 +08:00
AutoSizeAxes = Axes . Both ;
2018-10-29 13:07:06 +08:00
InternalChildren = new Drawable [ ]
{
2019-10-31 15:23:54 +08:00
marker = new Container
2018-10-29 13:07:06 +08:00
{
2018-10-29 15:15:04 +08:00
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2019-10-31 15:23:54 +08:00
AutoSizeAxes = Axes . Both ,
Children = new [ ]
{
new Circle
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2020-12-01 13:17:36 +08:00
Size = new Vector2 ( 20 ) ,
2019-10-31 15:23:54 +08:00
} ,
markerRing = new CircularContainer
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2020-12-01 13:17:36 +08:00
Size = new Vector2 ( 28 ) ,
2019-10-31 15:23:54 +08:00
Masking = true ,
BorderThickness = 2 ,
BorderColour = Color4 . White ,
Alpha = 0 ,
Child = new Box
{
RelativeSizeAxes = Axes . Both ,
Alpha = 0 ,
AlwaysPresent = true
}
}
}
2018-10-29 13:07:06 +08:00
}
} ;
}
2019-12-09 19:49:59 +08:00
protected override void LoadComplete ( )
2018-10-29 13:07:06 +08:00
{
2019-12-09 19:49:59 +08:00
base . LoadComplete ( ) ;
2018-10-29 13:07:06 +08:00
2019-12-09 19:49:59 +08:00
sliderPosition = slider . PositionBindable . GetBoundCopy ( ) ;
2019-12-10 10:20:08 +08:00
sliderPosition . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2019-10-31 15:23:54 +08:00
2019-12-10 10:20:08 +08:00
controlPointPosition = ControlPoint . Position . GetBoundCopy ( ) ;
controlPointPosition . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2019-10-31 15:23:54 +08:00
2020-12-01 13:17:36 +08:00
sliderScale = slider . ScaleBindable . GetBoundCopy ( ) ;
sliderScale . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2019-12-09 19:49:59 +08:00
IsSelected . BindValueChanged ( _ = > updateMarkerDisplay ( ) ) ;
2018-10-29 13:07:06 +08:00
2019-12-09 19:49:59 +08:00
updateMarkerDisplay ( ) ;
2018-10-29 13:07:06 +08:00
}
2019-10-31 15:23:54 +08:00
// The connecting path is excluded from positional input
2018-10-29 15:15:04 +08:00
public override bool ReceivePositionalInputAt ( Vector2 screenSpacePos ) = > marker . ReceivePositionalInputAt ( screenSpacePos ) ;
2019-12-09 19:49:59 +08:00
protected override bool OnHover ( HoverEvent e )
{
updateMarkerDisplay ( ) ;
2019-12-09 23:08:38 +08:00
return false ;
2019-12-09 19:49:59 +08:00
}
protected override void OnHoverLost ( HoverLostEvent e )
{
updateMarkerDisplay ( ) ;
}
2019-10-31 16:13:10 +08:00
protected override bool OnMouseDown ( MouseDownEvent e )
{
2019-11-13 16:28:18 +08:00
if ( RequestSelection = = null )
2019-11-12 17:35:28 +08:00
return false ;
2019-11-13 16:28:18 +08:00
switch ( e . Button )
2019-11-03 18:59:37 +08:00
{
2019-11-13 16:28:18 +08:00
case MouseButton . Left :
2019-12-09 19:49:59 +08:00
RequestSelection . Invoke ( this , e ) ;
2019-11-13 16:28:18 +08:00
return true ;
case MouseButton . Right :
if ( ! IsSelected . Value )
2019-12-09 19:49:59 +08:00
RequestSelection . Invoke ( this , e ) ;
2019-11-13 16:28:18 +08:00
return false ; // Allow context menu to show
2019-11-03 18:59:37 +08:00
}
return false ;
2019-10-31 16:13:10 +08:00
}
2019-11-13 16:28:18 +08:00
protected override bool OnClick ( ClickEvent e ) = > RequestSelection ! = null ;
2019-11-05 01:21:50 +08:00
2020-12-01 12:46:30 +08:00
private Vector2 dragStartPosition ;
2020-04-09 21:00:56 +08:00
protected override bool OnDragStart ( DragStartEvent e )
{
2020-04-23 11:17:11 +08:00
if ( RequestSelection = = null )
return false ;
2020-04-09 21:00:56 +08:00
if ( e . Button = = MouseButton . Left )
{
2020-12-01 12:46:30 +08:00
dragStartPosition = ControlPoint . Position . Value ;
2020-04-09 21:00:56 +08:00
changeHandler ? . BeginChange ( ) ;
return true ;
}
return false ;
}
2018-10-29 13:07:06 +08:00
2020-01-20 17:17:21 +08:00
protected override void OnDrag ( DragEvent e )
2018-10-29 13:07:06 +08:00
{
2019-12-09 19:49:59 +08:00
if ( ControlPoint = = slider . Path . ControlPoints [ 0 ] )
2018-10-29 14:36:43 +08:00
{
2019-11-07 13:00:12 +08: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 17:57:28 +08:00
var result = snapProvider ? . SnapScreenSpacePositionToValidTime ( e . ScreenSpaceMousePosition ) ;
Vector2 movementDelta = Parent . ToLocalSpace ( result ? . ScreenSpacePosition ? ? e . ScreenSpaceMousePosition ) - slider . Position ;
2019-11-07 13:00:12 +08:00
slider . Position + = movementDelta ;
2020-05-20 17:19:21 +08:00
slider . StartTime = result ? . Time ? ? slider . StartTime ;
2018-10-29 14:36:43 +08: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 18:53:31 +08:00
for ( int i = 1 ; i < slider . Path . ControlPoints . Count ; i + + )
slider . Path . ControlPoints [ i ] . Position . Value - = movementDelta ;
2018-10-29 14:36:43 +08:00
}
else
2020-12-01 12:46:30 +08:00
ControlPoint . Position . Value = dragStartPosition + ( e . MousePosition - e . MouseDownPosition ) ;
2018-10-29 13:07:06 +08:00
}
2020-04-09 21:00:56 +08:00
protected override void OnDragEnd ( DragEndEvent e ) = > changeHandler ? . EndChange ( ) ;
2019-12-09 19:49:59 +08: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 20:59:23 +08:00
2019-12-09 19:49:59 +08:00
if ( IsHovered | | IsSelected . Value )
2020-04-13 20:59:23 +08:00
colour = colour . Lighten ( 1 ) ;
2019-12-09 19:49:59 +08:00
marker . Colour = colour ;
2020-12-01 13:17:36 +08:00
marker . Scale = new Vector2 ( slider . Scale ) ;
2019-12-09 19:49:59 +08:00
}
2018-10-29 13:07:06 +08:00
}
}