2020-11-15 23:06:29 +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.
2022-06-17 15:37:17 +08:00
#nullable disable
2021-04-13 12:46:38 +08:00
using System ;
2020-11-15 23:06:29 +08:00
using System.Linq ;
using NUnit.Framework ;
using osu.Framework.Testing ;
2021-10-27 03:29:50 +08:00
using osu.Framework.Graphics.Cursor ;
using osu.Framework.Graphics.UserInterface ;
2020-11-15 23:06:29 +08:00
using osu.Game.Beatmaps ;
2021-10-27 03:29:50 +08:00
using osu.Game.Graphics.UserInterface ;
2020-11-15 23:06:29 +08:00
using osu.Game.Rulesets ;
2022-06-12 01:24:50 +08:00
using osu.Game.Rulesets.Edit ;
2020-11-15 23:06:29 +08:00
using osu.Game.Rulesets.Objects ;
using osu.Game.Rulesets.Osu ;
using osu.Game.Rulesets.Osu.Objects ;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components ;
2020-11-16 00:42:52 +08:00
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components ;
2021-04-22 14:41:21 +08:00
using osu.Game.Rulesets.Osu.UI ;
2020-11-15 23:06:29 +08:00
using osu.Game.Tests.Beatmaps ;
using osu.Game.Screens.Edit.Compose.Components ;
using osuTK ;
using osuTK.Input ;
namespace osu.Game.Tests.Visual.Editing
{
2022-11-24 13:32:20 +08:00
public partial class TestSceneComposerSelection : EditorTestScene
2020-11-15 23:06:29 +08:00
{
protected override Ruleset CreateEditorRuleset ( ) = > new OsuRuleset ( ) ;
protected override IBeatmap CreateBeatmap ( RulesetInfo ruleset ) = > new TestBeatmap ( ruleset , false ) ;
2021-09-26 23:22:58 +08:00
private ComposeBlueprintContainer blueprintContainer
= > Editor . ChildrenOfType < ComposeBlueprintContainer > ( ) . First ( ) ;
2020-11-16 03:51:35 +08:00
2021-10-27 03:29:50 +08:00
private ContextMenuContainer contextMenuContainer
= > Editor . ChildrenOfType < ContextMenuContainer > ( ) . First ( ) ;
2021-04-13 12:46:38 +08:00
private void moveMouseToObject ( Func < HitObject > targetFunc )
2021-04-13 12:29:37 +08:00
{
AddStep ( "move mouse to object" , ( ) = >
{
var pos = blueprintContainer . SelectionBlueprints
2021-04-27 14:40:35 +08:00
. First ( s = > s . Item = = targetFunc ( ) )
2021-04-13 12:29:37 +08:00
. ChildrenOfType < HitCirclePiece > ( )
. First ( ) . ScreenSpaceDrawQuad . Centre ;
InputManager . MoveMouseTo ( pos ) ;
} ) ;
}
2021-10-27 02:52:15 +08:00
[Test]
public void TestSelectAndShowContextMenu ( )
{
var addedObject = new HitCircle { StartTime = 100 , Position = new Vector2 ( 100 , 100 ) } ;
AddStep ( "add hitobject" , ( ) = > EditorBeatmap . Add ( addedObject ) ) ;
moveMouseToObject ( ( ) = > addedObject ) ;
AddStep ( "right click" , ( ) = > InputManager . Click ( MouseButton . Right ) ) ;
2021-10-27 04:24:53 +08:00
AddUntilStep ( "hitobject selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObject ) ;
AddUntilStep ( "context menu is visible" , ( ) = > contextMenuContainer . ChildrenOfType < OsuContextMenu > ( ) . Single ( ) . State = = MenuState . Open ) ;
2021-10-27 02:52:15 +08:00
}
2022-06-12 01:24:50 +08:00
[Test]
public void TestSelectAndShowContextMenuOutsideBounds ( )
{
var addedObject = new HitCircle { StartTime = 100 , Position = OsuPlayfield . BASE_SIZE } ;
AddStep ( "add hitobject" , ( ) = > EditorBeatmap . Add ( addedObject ) ) ;
AddStep ( "descale blueprint container" , ( ) = > this . ChildrenOfType < HitObjectComposer > ( ) . Single ( ) . Scale = new Vector2 ( 0.5f ) ) ;
2022-06-12 22:53:10 +08:00
AddStep ( "move mouse to bottom-right" , ( ) = > InputManager . MoveMouseTo ( blueprintContainer . ToScreenSpace ( blueprintContainer . LayoutRectangle . BottomRight + new Vector2 ( 10 ) ) ) ) ;
2022-06-12 01:24:50 +08:00
AddStep ( "right click" , ( ) = > InputManager . Click ( MouseButton . Right ) ) ;
AddUntilStep ( "hitobject selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObject ) ;
AddUntilStep ( "context menu is visible" , ( ) = > contextMenuContainer . ChildrenOfType < OsuContextMenu > ( ) . Single ( ) . State = = MenuState . Open ) ;
}
2021-04-22 17:47:04 +08:00
[Test]
public void TestNudgeSelection ( )
{
HitCircle [ ] addedObjects = null ;
AddStep ( "add hitobjects" , ( ) = > EditorBeatmap . AddRange ( addedObjects = new [ ]
{
new HitCircle { StartTime = 100 } ,
2021-04-26 06:45:50 +08:00
new HitCircle { StartTime = 200 , Position = new Vector2 ( 100 ) } ,
new HitCircle { StartTime = 300 , Position = new Vector2 ( 200 ) } ,
new HitCircle { StartTime = 400 , Position = new Vector2 ( 300 ) } ,
2021-04-22 17:47:04 +08:00
} ) ) ;
AddStep ( "select objects" , ( ) = > EditorBeatmap . SelectedHitObjects . AddRange ( addedObjects ) ) ;
AddStep ( "nudge forwards" , ( ) = > InputManager . Key ( Key . K ) ) ;
AddAssert ( "objects moved forwards in time" , ( ) = > addedObjects [ 0 ] . StartTime > 100 ) ;
AddStep ( "nudge backwards" , ( ) = > InputManager . Key ( Key . J ) ) ;
AddAssert ( "objects reverted to original position" , ( ) = > addedObjects [ 0 ] . StartTime = = 100 ) ;
}
2021-04-13 12:29:37 +08:00
[Test]
public void TestBasicSelect ( )
{
var addedObject = new HitCircle { StartTime = 100 } ;
AddStep ( "add hitobject" , ( ) = > EditorBeatmap . Add ( addedObject ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObject ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "left click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "hitobject selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObject ) ;
var addedObject2 = new HitCircle
{
StartTime = 100 ,
Position = new Vector2 ( 100 ) ,
} ;
AddStep ( "add one more hitobject" , ( ) = > EditorBeatmap . Add ( addedObject2 ) ) ;
AddAssert ( "selection unchanged" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObject ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObject2 ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "left click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "hitobject selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObject2 ) ;
}
[Test]
public void TestMultiSelect ( )
{
var addedObjects = new [ ]
{
new HitCircle { StartTime = 100 } ,
2021-04-26 06:45:50 +08:00
new HitCircle { StartTime = 200 , Position = new Vector2 ( 100 ) } ,
new HitCircle { StartTime = 300 , Position = new Vector2 ( 200 ) } ,
new HitCircle { StartTime = 400 , Position = new Vector2 ( 300 ) } ,
2021-04-13 12:29:37 +08:00
} ;
AddStep ( "add hitobjects" , ( ) = > EditorBeatmap . AddRange ( addedObjects ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObjects [ 0 ] ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "click first" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "hitobject selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObjects [ 0 ] ) ;
AddStep ( "hold control" , ( ) = > InputManager . PressKey ( Key . ControlLeft ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObjects [ 1 ] ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "click second" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "2 hitobjects selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Count = = 2 & & EditorBeatmap . SelectedHitObjects . Contains ( addedObjects [ 1 ] ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObjects [ 2 ] ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "click third" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "3 hitobjects selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Count = = 3 & & EditorBeatmap . SelectedHitObjects . Contains ( addedObjects [ 2 ] ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObjects [ 1 ] ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "click second" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "2 hitobjects selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Count = = 2 & & ! EditorBeatmap . SelectedHitObjects . Contains ( addedObjects [ 1 ] ) ) ;
}
2021-04-13 12:46:38 +08:00
[TestCase(false)]
[TestCase(true)]
public void TestMultiSelectFromDrag ( bool alreadySelectedBeforeDrag )
{
HitCircle [ ] addedObjects = null ;
AddStep ( "add hitobjects" , ( ) = > EditorBeatmap . AddRange ( addedObjects = new [ ]
{
new HitCircle { StartTime = 100 } ,
2021-04-26 06:45:50 +08:00
new HitCircle { StartTime = 200 , Position = new Vector2 ( 100 ) } ,
new HitCircle { StartTime = 300 , Position = new Vector2 ( 200 ) } ,
new HitCircle { StartTime = 400 , Position = new Vector2 ( 300 ) } ,
2021-04-13 12:46:38 +08:00
} ) ) ;
moveMouseToObject ( ( ) = > addedObjects [ 0 ] ) ;
AddStep ( "click first" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddStep ( "hold control" , ( ) = > InputManager . PressKey ( Key . ControlLeft ) ) ;
moveMouseToObject ( ( ) = > addedObjects [ 1 ] ) ;
if ( alreadySelectedBeforeDrag )
AddStep ( "click second" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddStep ( "mouse down on second" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
AddAssert ( "2 hitobjects selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Count = = 2 & & EditorBeatmap . SelectedHitObjects . Contains ( addedObjects [ 1 ] ) ) ;
AddStep ( "drag to centre" , ( ) = > InputManager . MoveMouseTo ( blueprintContainer . ScreenSpaceDrawQuad . Centre ) ) ;
AddAssert ( "positions changed" , ( ) = > addedObjects [ 0 ] . Position ! = Vector2 . Zero & & addedObjects [ 1 ] . Position ! = new Vector2 ( 50 ) ) ;
AddStep ( "release control" , ( ) = > InputManager . ReleaseKey ( Key . ControlLeft ) ) ;
AddStep ( "mouse up" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
}
2021-04-13 12:29:37 +08:00
[Test]
public void TestBasicDeselect ( )
{
var addedObject = new HitCircle { StartTime = 100 } ;
AddStep ( "add hitobject" , ( ) = > EditorBeatmap . Add ( addedObject ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObject ) ;
2021-04-13 12:29:37 +08:00
AddStep ( "left click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "hitobject selected" , ( ) = > EditorBeatmap . SelectedHitObjects . Single ( ) = = addedObject ) ;
AddStep ( "click away" , ( ) = >
{
InputManager . MoveMouseTo ( blueprintContainer . ScreenSpaceDrawQuad . Centre ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddAssert ( "selection lost" , ( ) = > EditorBeatmap . SelectedHitObjects . Count = = 0 ) ;
}
2020-11-15 23:06:29 +08:00
[Test]
2021-04-22 14:41:21 +08:00
public void TestQuickDeleteRemovesObjectInPlacement ( )
2020-11-15 23:06:29 +08:00
{
2021-04-22 14:41:21 +08:00
var addedObject = new HitCircle
{
StartTime = 0 ,
Position = OsuPlayfield . BASE_SIZE * 0.5f
} ;
AddStep ( "add hitobject" , ( ) = > EditorBeatmap . Add ( addedObject ) ) ;
AddStep ( "enter placement mode" , ( ) = > InputManager . PressKey ( Key . Number2 ) ) ;
moveMouseToObject ( ( ) = > addedObject ) ;
AddStep ( "hold shift" , ( ) = > InputManager . PressKey ( Key . ShiftLeft ) ) ;
AddStep ( "right click" , ( ) = > InputManager . Click ( MouseButton . Right ) ) ;
AddStep ( "release shift" , ( ) = > InputManager . ReleaseKey ( Key . ShiftLeft ) ) ;
AddAssert ( "no hitobjects in beatmap" , ( ) = > EditorBeatmap . HitObjects . Count = = 0 ) ;
}
[Test]
public void TestQuickDeleteRemovesObjectInSelection ( )
{
var addedObject = new HitCircle
{
StartTime = 0 ,
Position = OsuPlayfield . BASE_SIZE * 0.5f
} ;
2020-11-15 23:06:29 +08:00
AddStep ( "add hitobject" , ( ) = > EditorBeatmap . Add ( addedObject ) ) ;
AddStep ( "select added object" , ( ) = > EditorBeatmap . SelectedHitObjects . Add ( addedObject ) ) ;
2021-04-13 12:46:38 +08:00
moveMouseToObject ( ( ) = > addedObject ) ;
2021-04-13 12:29:37 +08:00
2020-11-15 23:06:29 +08:00
AddStep ( "hold shift" , ( ) = > InputManager . PressKey ( Key . ShiftLeft ) ) ;
2020-11-16 13:06:37 +08:00
AddStep ( "right click" , ( ) = > InputManager . Click ( MouseButton . Right ) ) ;
2020-11-15 23:06:29 +08:00
AddStep ( "release shift" , ( ) = > InputManager . ReleaseKey ( Key . ShiftLeft ) ) ;
AddAssert ( "no hitobjects in beatmap" , ( ) = > EditorBeatmap . HitObjects . Count = = 0 ) ;
}
[Test]
public void TestQuickDeleteRemovesSliderControlPoint ( )
{
2021-04-12 18:19:25 +08:00
Slider slider = null ;
2020-11-15 23:06:29 +08:00
2020-11-16 03:52:58 +08:00
PathControlPoint [ ] points =
2020-11-15 23:06:29 +08:00
{
new PathControlPoint ( ) ,
new PathControlPoint ( new Vector2 ( 50 , 0 ) ) ,
new PathControlPoint ( new Vector2 ( 100 , 0 ) )
} ;
AddStep ( "add slider" , ( ) = >
{
2021-04-12 18:19:25 +08:00
slider = new Slider
{
StartTime = 1000 ,
Path = new SliderPath ( points )
} ;
2020-11-15 23:06:29 +08:00
EditorBeatmap . Add ( slider ) ;
} ) ;
AddStep ( "select added slider" , ( ) = > EditorBeatmap . SelectedHitObjects . Add ( slider ) ) ;
AddStep ( "move mouse to controlpoint" , ( ) = >
{
2020-11-16 03:52:33 +08:00
var pos = blueprintContainer . ChildrenOfType < PathControlPointPiece > ( ) . ElementAt ( 1 ) . ScreenSpaceDrawQuad . Centre ;
2020-11-15 23:06:29 +08:00
InputManager . MoveMouseTo ( pos ) ;
} ) ;
AddStep ( "hold shift" , ( ) = > InputManager . PressKey ( Key . ShiftLeft ) ) ;
2020-11-16 13:06:37 +08:00
AddStep ( "right click" , ( ) = > InputManager . Click ( MouseButton . Right ) ) ;
2020-11-15 23:06:29 +08:00
AddAssert ( "slider has 2 points" , ( ) = > slider . Path . ControlPoints . Count = = 2 ) ;
2020-11-16 13:06:37 +08:00
AddStep ( "right click" , ( ) = > InputManager . Click ( MouseButton . Right ) ) ;
2021-04-13 12:03:14 +08:00
// second click should nuke the object completely.
2020-11-16 13:06:37 +08:00
AddAssert ( "no hitobjects in beatmap" , ( ) = > EditorBeatmap . HitObjects . Count = = 0 ) ;
AddStep ( "release shift" , ( ) = > InputManager . ReleaseKey ( Key . ShiftLeft ) ) ;
2020-11-15 23:06:29 +08:00
}
}
}