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-11-16 16:12:24 +08:00
using System.Linq ;
using osu.Framework.Allocation ;
using osu.Framework.Timing ;
2018-11-26 15:08:56 +08:00
using osu.Game.Rulesets.Mania.Edit.Blueprints ;
2018-11-16 16:12:24 +08:00
using osu.Game.Rulesets.Mania.Objects ;
2018-11-19 15:19:56 +08:00
using osu.Game.Rulesets.UI ;
2018-11-16 16:12:24 +08:00
using osu.Game.Rulesets.UI.Scrolling ;
using osu.Game.Screens.Edit.Compose.Components ;
2018-11-26 10:47:48 +08:00
using osuTK ;
2018-11-16 16:12:24 +08:00
namespace osu.Game.Rulesets.Mania.Edit
{
2018-11-19 15:58:11 +08:00
public class ManiaSelectionHandler : SelectionHandler
2018-11-16 16:12:24 +08:00
{
[Resolved]
private IScrollingInfo scrollingInfo { get ; set ; }
[Resolved]
private IManiaHitObjectComposer composer { get ; set ; }
private IClock editorClock ;
[BackgroundDependencyLoader]
private void load ( IAdjustableClock clock )
{
editorClock = clock ;
}
2019-11-06 16:27:41 +08:00
public override bool HandleMovement ( MoveSelectionEvent moveEvent )
2018-11-16 16:12:24 +08:00
{
2019-10-08 18:08:23 +08:00
var maniaBlueprint = ( ManiaSelectionBlueprint ) moveEvent . Blueprint ;
2019-10-21 16:04:56 +08:00
int lastColumn = maniaBlueprint . DrawableObject . HitObject . Column ;
2019-10-08 17:57:03 +08:00
adjustOrigins ( maniaBlueprint ) ;
2019-10-08 18:08:23 +08:00
performDragMovement ( moveEvent ) ;
performColumnMovement ( lastColumn , moveEvent ) ;
2018-11-26 15:08:56 +08:00
2019-11-06 16:27:41 +08:00
return true ;
2018-11-26 15:08:56 +08:00
}
/// <summary>
/// Ensures that the position of hitobjects remains centred to the mouse position.
/// E.g. The hitobject position will change if the editor scrolls while a hitobject is dragged.
/// </summary>
/// <param name="reference">The <see cref="ManiaSelectionBlueprint"/> that received the drag event.</param>
private void adjustOrigins ( ManiaSelectionBlueprint reference )
{
2019-10-21 16:04:56 +08:00
var referenceParent = ( HitObjectContainer ) reference . DrawableObject . Parent ;
2018-11-26 15:08:56 +08:00
2019-10-21 16:04:56 +08:00
float offsetFromReferenceOrigin = reference . DragPosition . Y - reference . DrawableObject . OriginPosition . Y ;
2018-11-30 13:21:20 +08:00
float targetPosition = referenceParent . ToLocalSpace ( reference . ScreenSpaceDragPosition ) . Y - offsetFromReferenceOrigin ;
2018-11-26 15:08:56 +08:00
// Flip the vertical coordinate space when scrolling downwards
if ( scrollingInfo . Direction . Value = = ScrollingDirection . Down )
targetPosition = targetPosition - referenceParent . DrawHeight ;
2019-10-21 16:04:56 +08:00
float movementDelta = targetPosition - reference . DrawableObject . Position . Y ;
2018-11-26 15:08:56 +08:00
foreach ( var b in SelectedBlueprints . OfType < ManiaSelectionBlueprint > ( ) )
2019-10-21 16:04:56 +08:00
b . DrawableObject . Y + = movementDelta ;
2018-11-26 15:08:56 +08:00
}
2019-10-08 18:08:23 +08:00
private void performDragMovement ( MoveSelectionEvent moveEvent )
2018-11-26 15:08:56 +08:00
{
2019-10-17 17:00:15 +08:00
float delta = moveEvent . InstantDelta . Y ;
// When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen.
// This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height.
if ( scrollingInfo . Direction . Value = = ScrollingDirection . Down )
2019-10-21 16:04:56 +08:00
delta - = moveEvent . Blueprint . DrawableObject . Parent . DrawHeight ;
2019-10-17 17:00:15 +08:00
2018-11-26 15:08:56 +08:00
foreach ( var b in SelectedBlueprints )
2018-11-16 16:12:24 +08:00
{
2019-10-21 16:04:56 +08:00
var hitObject = b . DrawableObject ;
2018-11-19 15:19:56 +08:00
var objectParent = ( HitObjectContainer ) hitObject . Parent ;
2018-11-16 16:12:24 +08:00
2019-10-17 17:00:15 +08:00
// StartTime could be used to adjust the position if only one movement event was received per frame.
// However this is not the case and ScrollingHitObjectContainer performs movement in UpdateAfterChildren() so the position must also be updated to be valid for further movement events
hitObject . Y + = delta ;
2018-11-16 16:12:24 +08:00
2019-10-17 17:00:15 +08:00
float targetPosition = hitObject . Position . Y ;
2018-11-16 16:12:24 +08:00
2019-10-17 17:00:15 +08:00
// The scrolling algorithm always assumes an anchor at the top of the screen, so the position must be flipped when scrolling downwards to reflect a top anchor
2018-11-16 16:12:24 +08:00
if ( scrollingInfo . Direction . Value = = ScrollingDirection . Down )
2019-10-17 17:00:15 +08:00
targetPosition = - targetPosition ;
2018-11-16 16:12:24 +08:00
2018-11-19 15:19:56 +08:00
objectParent . Remove ( hitObject ) ;
2018-11-16 16:12:24 +08:00
hitObject . HitObject . StartTime = scrollingInfo . Algorithm . TimeAt ( targetPosition ,
editorClock . CurrentTime ,
scrollingInfo . TimeRange . Value ,
objectParent . DrawHeight ) ;
2018-11-19 15:19:56 +08:00
objectParent . Add ( hitObject ) ;
2018-11-16 16:12:24 +08:00
}
}
2019-10-08 18:08:23 +08:00
private void performColumnMovement ( int lastColumn , MoveSelectionEvent moveEvent )
2018-11-16 16:12:24 +08:00
{
2019-10-08 18:08:23 +08:00
var currentColumn = composer . ColumnAt ( moveEvent . ScreenSpacePosition ) ;
2019-10-08 17:57:03 +08:00
if ( currentColumn = = null )
2018-11-16 16:12:24 +08:00
return ;
2019-10-08 17:57:03 +08:00
int columnDelta = currentColumn . Index - lastColumn ;
2018-11-16 16:12:24 +08:00
if ( columnDelta = = 0 )
return ;
int minColumn = int . MaxValue ;
int maxColumn = int . MinValue ;
foreach ( var obj in SelectedHitObjects . OfType < ManiaHitObject > ( ) )
{
if ( obj . Column < minColumn )
minColumn = obj . Column ;
if ( obj . Column > maxColumn )
maxColumn = obj . Column ;
}
columnDelta = MathHelper . Clamp ( columnDelta , - minColumn , composer . TotalColumns - 1 - maxColumn ) ;
foreach ( var obj in SelectedHitObjects . OfType < ManiaHitObject > ( ) )
obj . Column + = columnDelta ;
}
}
}