mirror of
https://github.com/ppy/osu
synced 2025-01-10 08:09:40 +00:00
Merge branch 'master' into auto-addition2
This commit is contained in:
commit
787d3dceea
@ -118,5 +118,45 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
AddAssert("all objects in last column", () => EditorBeatmap.HitObjects.All(ho => ((ManiaHitObject)ho).Column == 3));
|
||||
AddAssert("all objects remain selected", () => EditorBeatmap.SelectedHitObjects.SequenceEqual(EditorBeatmap.HitObjects));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOffScreenObjectsRemainSelectedOnHorizontalFlip()
|
||||
{
|
||||
AddStep("create objects", () =>
|
||||
{
|
||||
for (int i = 0; i < 20; ++i)
|
||||
EditorBeatmap.Add(new Note { StartTime = 1000 * i, Column = i % 4 });
|
||||
});
|
||||
|
||||
AddStep("select everything", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||
AddStep("flip", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.H);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
|
||||
AddAssert("all objects remain selected", () => EditorBeatmap.SelectedHitObjects.SequenceEqual(EditorBeatmap.HitObjects));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOffScreenObjectsRemainSelectedOnVerticalFlip()
|
||||
{
|
||||
AddStep("create objects", () =>
|
||||
{
|
||||
for (int i = 0; i < 20; ++i)
|
||||
EditorBeatmap.Add(new Note { StartTime = 1000 * i, Column = i % 4 });
|
||||
});
|
||||
|
||||
AddStep("select everything", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||
AddStep("flip", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.J);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
|
||||
AddAssert("all objects remain selected", () => EditorBeatmap.SelectedHitObjects.SequenceEqual(EditorBeatmap.HitObjects.Reverse()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
int firstColumn = flipOverOrigin ? 0 : selectedObjects.Min(ho => ho.Column);
|
||||
int lastColumn = flipOverOrigin ? (int)EditorBeatmap.BeatmapInfo.Difficulty.CircleSize - 1 : selectedObjects.Max(ho => ho.Column);
|
||||
|
||||
EditorBeatmap.PerformOnSelection(hitObject =>
|
||||
performOnSelection(maniaObject =>
|
||||
{
|
||||
var maniaObject = (ManiaHitObject)hitObject;
|
||||
maniaPlayfield.Remove(maniaObject);
|
||||
maniaObject.Column = firstColumn + (lastColumn - maniaObject.Column);
|
||||
maniaPlayfield.Add(maniaObject);
|
||||
@ -71,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
double selectionStartTime = selectedObjects.Min(ho => ho.StartTime);
|
||||
double selectionEndTime = selectedObjects.Max(ho => ho.GetEndTime());
|
||||
|
||||
EditorBeatmap.PerformOnSelection(hitObject =>
|
||||
performOnSelection(hitObject =>
|
||||
{
|
||||
hitObject.StartTime = selectionStartTime + (selectionEndTime - hitObject.GetEndTime());
|
||||
});
|
||||
@ -117,14 +116,21 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
|
||||
columnDelta = Math.Clamp(columnDelta, -minColumn, maniaPlayfield.TotalColumns - 1 - maxColumn);
|
||||
|
||||
EditorBeatmap.PerformOnSelection(h =>
|
||||
performOnSelection(h =>
|
||||
{
|
||||
maniaPlayfield.Remove(h);
|
||||
((ManiaHitObject)h).Column += columnDelta;
|
||||
h.Column += columnDelta;
|
||||
maniaPlayfield.Add(h);
|
||||
});
|
||||
}
|
||||
|
||||
// `HitObjectUsageEventBuffer`'s usage transferal flows and the playfield's `SetKeepAlive()` functionality do not combine well with this operation's usage pattern,
|
||||
private void performOnSelection(Action<ManiaHitObject> action)
|
||||
{
|
||||
var selectedObjects = EditorBeatmap.SelectedHitObjects.OfType<ManiaHitObject>().ToArray();
|
||||
|
||||
EditorBeatmap.PerformOnSelection(h => action.Invoke((ManiaHitObject)h));
|
||||
|
||||
// `HitObjectUsageEventBuffer`'s usage transferal flows and the playfield's `SetKeepAlive()` functionality do not combine well with mania's usage patterns,
|
||||
// leading to selections being sometimes partially dropped if some of the objects being moved are off screen
|
||||
// (check blame for detailed explanation).
|
||||
// thus, ensure that selection is preserved manually.
|
||||
|
55
osu.Game.Rulesets.Osu.Tests/Editor/TestSceneToolSwitching.cs
Normal file
55
osu.Game.Rulesets.Osu.Tests/Editor/TestSceneToolSwitching.cs
Normal file
@ -0,0 +1,55 @@
|
||||
// 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.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
{
|
||||
public partial class TestSceneToolSwitching : EditorTestScene
|
||||
{
|
||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||
|
||||
[Test]
|
||||
public void TestSliderAnchorMoveOperationEndsOnSwitchingTool()
|
||||
{
|
||||
var initialPosition = Vector2.Zero;
|
||||
|
||||
AddStep("store original anchor position", () => initialPosition = EditorBeatmap.HitObjects.OfType<Slider>().First().Path.ControlPoints.ElementAt(1).Position);
|
||||
AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.OfType<Slider>().First()));
|
||||
AddStep("move to second anchor", () => InputManager.MoveMouseTo(this.ChildrenOfType<PathControlPointPiece<Slider>>().ElementAt(1)));
|
||||
AddStep("start dragging", () => InputManager.PressButton(MouseButton.Left));
|
||||
AddStep("drag away", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(0, -200)));
|
||||
AddStep("switch tool", () => InputManager.PressButton(MouseButton.Button1));
|
||||
AddStep("undo", () => Editor.Undo());
|
||||
AddAssert("anchor back at original position",
|
||||
() => EditorBeatmap.HitObjects.OfType<Slider>().First().Path.ControlPoints.ElementAt(1).Position,
|
||||
() => Is.EqualTo(initialPosition));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSliderAnchorCreationOperationEndsOnSwitchingTool()
|
||||
{
|
||||
AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.OfType<Slider>().First()));
|
||||
AddStep("move to second anchor", () => InputManager.MoveMouseTo(this.ChildrenOfType<PathControlPointPiece<Slider>>().ElementAt(1), new Vector2(-50, 0)));
|
||||
AddStep("quick-create anchor", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
AddStep("drag away", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(0, -200)));
|
||||
AddStep("switch tool", () => InputManager.PressKey(Key.Number3));
|
||||
AddStep("drag away further", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(0, -200)));
|
||||
AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.OfType<Slider>().First()));
|
||||
AddStep("undo", () => Editor.Undo());
|
||||
AddAssert("slider has three anchors again", () => EditorBeatmap.HitObjects.OfType<Slider>().First().Path.ControlPoints, () => Has.Count.EqualTo(3));
|
||||
}
|
||||
}
|
||||
}
|
@ -333,6 +333,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
base.Dispose(isDisposing);
|
||||
foreach (var p in Pieces)
|
||||
p.ControlPoint.Changed -= controlPointChanged;
|
||||
|
||||
if (draggedControlPointIndex >= 0)
|
||||
DragEnded();
|
||||
}
|
||||
|
||||
private void selectionRequested(PathControlPointPiece<T> piece, MouseButtonEvent e)
|
||||
@ -392,7 +395,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
private Vector2[] dragStartPositions;
|
||||
private PathType?[] dragPathTypes;
|
||||
private int draggedControlPointIndex;
|
||||
private int draggedControlPointIndex = -1;
|
||||
private HashSet<PathControlPoint> selectedControlPoints;
|
||||
|
||||
private List<MenuItem> curveTypeItems;
|
||||
@ -473,7 +476,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
EnsureValidPathTypes();
|
||||
}
|
||||
|
||||
public void DragEnded() => changeHandler?.EndChange();
|
||||
public void DragEnded()
|
||||
{
|
||||
changeHandler?.EndChange();
|
||||
draggedControlPointIndex = -1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -178,6 +178,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
{
|
||||
base.OnDeselected();
|
||||
|
||||
if (placementControlPoint != null)
|
||||
endControlPointPlacement();
|
||||
|
||||
updateVisualDefinition();
|
||||
BodyPiece.RecyclePath();
|
||||
}
|
||||
@ -377,13 +380,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
if (placementControlPoint != null)
|
||||
{
|
||||
if (IsDragged)
|
||||
ControlPointVisualiser?.DragEnded();
|
||||
endControlPointPlacement();
|
||||
}
|
||||
|
||||
placementControlPoint = null;
|
||||
changeHandler?.EndChange();
|
||||
}
|
||||
private void endControlPointPlacement()
|
||||
{
|
||||
if (IsDragged)
|
||||
ControlPointVisualiser?.DragEnded();
|
||||
|
||||
placementControlPoint = null;
|
||||
changeHandler?.EndChange();
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
|
@ -5,10 +5,13 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
@ -55,6 +58,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
MaxValue = 360,
|
||||
Precision = 1
|
||||
},
|
||||
KeyboardStep = 1f,
|
||||
Instantaneous = true
|
||||
},
|
||||
rotationOrigin = new EditorRadioButtonCollection
|
||||
@ -126,6 +130,17 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
if (IsLoaded)
|
||||
rotationHandler.Commit();
|
||||
}
|
||||
|
||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
{
|
||||
if (e.Action == GlobalAction.Select && !e.Repeat)
|
||||
{
|
||||
this.HidePopover();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnPressed(e);
|
||||
}
|
||||
}
|
||||
|
||||
public enum RotationOrigin
|
||||
|
@ -5,11 +5,14 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
@ -70,6 +73,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
Value = 1,
|
||||
Default = 1,
|
||||
},
|
||||
KeyboardStep = 0.01f,
|
||||
Instantaneous = true
|
||||
},
|
||||
scaleOrigin = new EditorRadioButtonCollection
|
||||
@ -282,6 +286,17 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
if (IsLoaded) scaleHandler.Commit();
|
||||
}
|
||||
|
||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
{
|
||||
if (e.Action == GlobalAction.Select && !e.Repeat)
|
||||
{
|
||||
this.HidePopover();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnPressed(e);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ScaleOrigin
|
||||
|
@ -96,6 +96,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
|
||||
public override IAdjustableAudioComponent Audio { get; }
|
||||
public override Playfield Playfield { get; }
|
||||
public override PlayfieldAdjustmentContainer PlayfieldAdjustmentContainer { get; }
|
||||
public override Container Overlays { get; }
|
||||
public override Container FrameStableComponents { get; }
|
||||
public override IFrameStableClock FrameStableClock { get; }
|
||||
|
@ -284,6 +284,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public override IAdjustableAudioComponent Audio { get; }
|
||||
public override Playfield Playfield { get; }
|
||||
public override PlayfieldAdjustmentContainer PlayfieldAdjustmentContainer { get; }
|
||||
public override Container Overlays { get; }
|
||||
public override Container FrameStableComponents { get; }
|
||||
public override IFrameStableClock FrameStableClock { get; }
|
||||
|
@ -17,9 +17,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
protected override void AddMetadata(string metadata, LinkFlowContainer loaded)
|
||||
{
|
||||
if (SearchAction != null)
|
||||
loaded.AddLink(metadata, () => SearchAction(metadata));
|
||||
loaded.AddLink(metadata, () => SearchAction($@"source=""""{metadata}"""""));
|
||||
else
|
||||
loaded.AddLink(metadata, LinkAction.SearchBeatmapSet, metadata);
|
||||
loaded.AddLink(metadata, LinkAction.SearchBeatmapSet, $@"source=""""{metadata}""""");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,22 +65,20 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public override Playfield Playfield => playfield.Value;
|
||||
|
||||
public override PlayfieldAdjustmentContainer PlayfieldAdjustmentContainer => playfieldAdjustmentContainer;
|
||||
|
||||
public override Container Overlays { get; } = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
public override IAdjustableAudioComponent Audio => audioContainer;
|
||||
|
||||
private readonly AudioContainer audioContainer = new AudioContainer { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
/// <summary>
|
||||
/// A container which encapsulates the <see cref="Playfield"/> and provides any adjustments to
|
||||
/// ensure correct scale and position.
|
||||
/// </summary>
|
||||
public virtual PlayfieldAdjustmentContainer PlayfieldAdjustmentContainer { get; private set; }
|
||||
|
||||
public override Container FrameStableComponents { get; } = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
public override IFrameStableClock FrameStableClock => frameStabilityContainer;
|
||||
|
||||
private readonly PlayfieldAdjustmentContainer playfieldAdjustmentContainer;
|
||||
|
||||
private bool allowBackwardsSeeks;
|
||||
|
||||
public override bool AllowBackwardsSeeks
|
||||
@ -146,6 +144,7 @@ namespace osu.Game.Rulesets.UI
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
KeyBindingInputManager = CreateInputManager();
|
||||
playfieldAdjustmentContainer = CreatePlayfieldAdjustmentContainer();
|
||||
playfield = new Lazy<Playfield>(() => CreatePlayfield().With(p =>
|
||||
{
|
||||
p.NewResult += (_, r) => NewResult?.Invoke(r);
|
||||
@ -197,8 +196,7 @@ namespace osu.Game.Rulesets.UI
|
||||
audioContainer.WithChild(KeyBindingInputManager
|
||||
.WithChildren(new Drawable[]
|
||||
{
|
||||
PlayfieldAdjustmentContainer = CreatePlayfieldAdjustmentContainer()
|
||||
.WithChild(Playfield),
|
||||
playfieldAdjustmentContainer.WithChild(Playfield),
|
||||
Overlays
|
||||
})),
|
||||
}
|
||||
@ -456,6 +454,12 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public abstract Playfield Playfield { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A container which encapsulates the <see cref="Playfield"/> and provides any adjustments to
|
||||
/// ensure correct scale and position.
|
||||
/// </summary>
|
||||
public abstract PlayfieldAdjustmentContainer PlayfieldAdjustmentContainer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Content to be placed above hitobjects. Will be affected by frame stability and adjustments applied to <see cref="Audio"/>.
|
||||
/// </summary>
|
||||
|
@ -252,7 +252,7 @@ namespace osu.Game.Screens.Play
|
||||
PlayfieldSkinLayer.Position = ToLocalSpace(playfieldScreenSpaceDrawQuad.TopLeft);
|
||||
PlayfieldSkinLayer.Width = (ToLocalSpace(playfieldScreenSpaceDrawQuad.TopRight) - ToLocalSpace(playfieldScreenSpaceDrawQuad.TopLeft)).Length;
|
||||
PlayfieldSkinLayer.Height = (ToLocalSpace(playfieldScreenSpaceDrawQuad.BottomLeft) - ToLocalSpace(playfieldScreenSpaceDrawQuad.TopLeft)).Length;
|
||||
PlayfieldSkinLayer.Rotation = drawableRuleset.Playfield.Rotation;
|
||||
PlayfieldSkinLayer.Rotation = drawableRuleset.PlayfieldAdjustmentContainer.Rotation;
|
||||
}
|
||||
|
||||
float? lowestTopScreenSpaceLeft = null;
|
||||
|
@ -154,6 +154,9 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
bool wasPlaying = IsPlaying;
|
||||
|
||||
if (wasPlaying && Looping)
|
||||
Stop();
|
||||
|
||||
// Remove all pooled samples (return them to the pool), and dispose the rest.
|
||||
samplesContainer.RemoveAll(s => s.IsInPool, false);
|
||||
samplesContainer.Clear();
|
||||
|
Loading…
Reference in New Issue
Block a user