mirror of
https://github.com/ppy/osu.git
synced 2025-01-31 22:22:55 +08:00
Merge pull request #3736 from smoogipoo/inter-column-movements
Implement inter-column note movements
This commit is contained in:
commit
02ef187c04
@ -46,5 +46,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
protected override void AddHitObject(DrawableHitObject hitObject) => column.Add((DrawableManiaHitObject)hitObject);
|
protected override void AddHitObject(DrawableHitObject hitObject) => column.Add((DrawableManiaHitObject)hitObject);
|
||||||
|
|
||||||
public Column ColumnAt(Vector2 screenSpacePosition) => column;
|
public Column ColumnAt(Vector2 screenSpacePosition) => column;
|
||||||
|
|
||||||
|
public int TotalColumns => 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,37 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Rulesets.Mania.Edit;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
public abstract class ManiaSelectionBlueprintTestCase : SelectionBlueprintTestCase
|
[Cached(Type = typeof(IManiaHitObjectComposer))]
|
||||||
|
public abstract class ManiaSelectionBlueprintTestCase : SelectionBlueprintTestCase, IManiaHitObjectComposer
|
||||||
{
|
{
|
||||||
[Cached(Type = typeof(IAdjustableClock))]
|
[Cached(Type = typeof(IAdjustableClock))]
|
||||||
private readonly IAdjustableClock clock = new StopwatchClock();
|
private readonly IAdjustableClock clock = new StopwatchClock();
|
||||||
|
|
||||||
|
private readonly Column column;
|
||||||
|
|
||||||
|
protected ManiaSelectionBlueprintTestCase()
|
||||||
|
{
|
||||||
|
Add(column = new Column(0)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AccentColour = Color4.OrangeRed,
|
||||||
|
Clock = new FramedClock(new StopwatchClock()), // No scroll
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Column ColumnAt(Vector2 screenSpacePosition) => column;
|
||||||
|
|
||||||
|
public int TotalColumns => 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
{
|
{
|
||||||
public class ManiaSelectionBlueprint : SelectionBlueprint
|
public class ManiaSelectionBlueprint : SelectionBlueprint
|
||||||
{
|
{
|
||||||
|
public Vector2 ScreenSpaceDragPosition { get; private set; }
|
||||||
|
public Vector2 DragPosition { get; private set; }
|
||||||
|
|
||||||
protected new DrawableManiaHitObject HitObject => (DrawableManiaHitObject)base.HitObject;
|
protected new DrawableManiaHitObject HitObject => (DrawableManiaHitObject)base.HitObject;
|
||||||
|
|
||||||
protected IClock EditorClock { get; private set; }
|
protected IClock EditorClock { get; private set; }
|
||||||
@ -22,6 +25,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IScrollingInfo scrollingInfo { get; set; }
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IManiaHitObjectComposer composer { get; set; }
|
||||||
|
|
||||||
public ManiaSelectionBlueprint(DrawableHitObject hitObject)
|
public ManiaSelectionBlueprint(DrawableHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
@ -41,27 +47,22 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
Position = Parent.ToLocalSpace(HitObject.ToScreenSpace(Vector2.Zero));
|
Position = Parent.ToLocalSpace(HitObject.ToScreenSpace(Vector2.Zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AdjustPosition(DragEvent dragEvent)
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
{
|
{
|
||||||
var objectParent = HitObject.Parent;
|
ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
|
||||||
|
DragPosition = HitObject.ToLocalSpace(e.ScreenSpaceMousePosition);
|
||||||
|
|
||||||
// Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame
|
return base.OnMouseDown(e);
|
||||||
// without the position having been updated by the parenting ScrollingHitObjectContainer
|
}
|
||||||
HitObject.Y += dragEvent.Delta.Y;
|
|
||||||
|
|
||||||
float targetPosition;
|
protected override bool OnDrag(DragEvent e)
|
||||||
|
{
|
||||||
|
var result = base.OnDrag(e);
|
||||||
|
|
||||||
// If we're scrolling downwards, a position of 0 is actually further away from the hit target
|
ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
|
||||||
// so we need to flip the vertical coordinate in the hitobject container's space
|
DragPosition = HitObject.ToLocalSpace(e.ScreenSpaceMousePosition);
|
||||||
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
|
|
||||||
targetPosition = -HitObject.Position.Y;
|
|
||||||
else
|
|
||||||
targetPosition = HitObject.Position.Y;
|
|
||||||
|
|
||||||
HitObject.HitObject.StartTime = scrollingInfo.Algorithm.TimeAt(targetPosition,
|
return result;
|
||||||
EditorClock.CurrentTime,
|
|
||||||
scrollingInfo.TimeRange.Value,
|
|
||||||
objectParent.DrawHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Show()
|
public override void Show()
|
||||||
|
@ -9,5 +9,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
public interface IManiaHitObjectComposer
|
public interface IManiaHitObjectComposer
|
||||||
{
|
{
|
||||||
Column ColumnAt(Vector2 screenSpacePosition);
|
Column ColumnAt(Vector2 screenSpacePosition);
|
||||||
|
|
||||||
|
int TotalColumns { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit
|
namespace osu.Game.Rulesets.Mania.Edit
|
||||||
@ -38,6 +39,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
|
public int TotalColumns => ((ManiaPlayfield)RulesetContainer.Playfield).TotalColumns;
|
||||||
|
|
||||||
protected override RulesetContainer<ManiaHitObject> CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
protected override RulesetContainer<ManiaHitObject> CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||||
{
|
{
|
||||||
RulesetContainer = new ManiaEditRulesetContainer(ruleset, beatmap);
|
RulesetContainer = new ManiaEditRulesetContainer(ruleset, beatmap);
|
||||||
@ -54,6 +57,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
new HoldNoteCompositionTool()
|
new HoldNoteCompositionTool()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler();
|
||||||
|
|
||||||
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
|
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
switch (hitObject)
|
switch (hitObject)
|
||||||
|
125
osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
Normal file
125
osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Edit
|
||||||
|
{
|
||||||
|
public class ManiaSelectionHandler : SelectionHandler
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IScrollingInfo scrollingInfo { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IManiaHitObjectComposer composer { get; set; }
|
||||||
|
|
||||||
|
private IClock editorClock;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IAdjustableClock clock)
|
||||||
|
{
|
||||||
|
editorClock = clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent)
|
||||||
|
{
|
||||||
|
adjustOrigins((ManiaSelectionBlueprint)blueprint);
|
||||||
|
performDragMovement(dragEvent);
|
||||||
|
performColumnMovement(dragEvent);
|
||||||
|
|
||||||
|
base.HandleDrag(blueprint, dragEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
var referenceParent = (HitObjectContainer)reference.HitObject.Parent;
|
||||||
|
|
||||||
|
float offsetFromReferenceOrigin = reference.DragPosition.Y - reference.HitObject.OriginPosition.Y;
|
||||||
|
float targetPosition = referenceParent.ToLocalSpace(reference.ScreenSpaceDragPosition).Y - offsetFromReferenceOrigin;
|
||||||
|
|
||||||
|
// Flip the vertical coordinate space when scrolling downwards
|
||||||
|
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
|
||||||
|
targetPosition = targetPosition - referenceParent.DrawHeight;
|
||||||
|
|
||||||
|
float movementDelta = targetPosition - reference.HitObject.Position.Y;
|
||||||
|
|
||||||
|
foreach (var b in SelectedBlueprints.OfType<ManiaSelectionBlueprint>())
|
||||||
|
b.HitObject.Y += movementDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performDragMovement(DragEvent dragEvent)
|
||||||
|
{
|
||||||
|
foreach (var b in SelectedBlueprints)
|
||||||
|
{
|
||||||
|
var hitObject = b.HitObject;
|
||||||
|
|
||||||
|
var objectParent = (HitObjectContainer)hitObject.Parent;
|
||||||
|
|
||||||
|
// Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame
|
||||||
|
// without the position having been updated by the parenting ScrollingHitObjectContainer
|
||||||
|
hitObject.Y += dragEvent.Delta.Y;
|
||||||
|
|
||||||
|
float targetPosition;
|
||||||
|
|
||||||
|
// If we're scrolling downwards, a position of 0 is actually further away from the hit target
|
||||||
|
// so we need to flip the vertical coordinate in the hitobject container's space
|
||||||
|
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
|
||||||
|
targetPosition = -hitObject.Position.Y;
|
||||||
|
else
|
||||||
|
targetPosition = hitObject.Position.Y;
|
||||||
|
|
||||||
|
objectParent.Remove(hitObject);
|
||||||
|
|
||||||
|
hitObject.HitObject.StartTime = scrollingInfo.Algorithm.TimeAt(targetPosition,
|
||||||
|
editorClock.CurrentTime,
|
||||||
|
scrollingInfo.TimeRange.Value,
|
||||||
|
objectParent.DrawHeight);
|
||||||
|
|
||||||
|
objectParent.Add(hitObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performColumnMovement(DragEvent dragEvent)
|
||||||
|
{
|
||||||
|
var lastColumn = composer.ColumnAt(dragEvent.ScreenSpaceLastMousePosition);
|
||||||
|
var currentColumn = composer.ColumnAt(dragEvent.ScreenSpaceMousePosition);
|
||||||
|
if (lastColumn == null || currentColumn == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int columnDelta = currentColumn.Index - lastColumn.Index;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Types;
|
using osu.Game.Rulesets.Mania.Objects.Types;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -8,7 +9,13 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
{
|
{
|
||||||
public abstract class ManiaHitObject : HitObject, IHasColumn
|
public abstract class ManiaHitObject : HitObject, IHasColumn
|
||||||
{
|
{
|
||||||
public virtual int Column { get; set; }
|
public readonly Bindable<int> ColumnBindable = new Bindable<int>();
|
||||||
|
|
||||||
|
public virtual int Column
|
||||||
|
{
|
||||||
|
get => ColumnBindable;
|
||||||
|
set => ColumnBindable.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
||||||
}
|
}
|
||||||
|
@ -145,11 +145,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
HitObjectContainer.Add(hitObject);
|
HitObjectContainer.Add(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Remove(DrawableHitObject h)
|
public override bool Remove(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
h.OnNewResult -= OnNewResult;
|
if (!base.Remove(h))
|
||||||
|
return false;
|
||||||
|
|
||||||
HitObjectContainer.Remove(h);
|
h.OnNewResult -= OnNewResult;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
|
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
|
||||||
|
|
||||||
public override void Remove(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Remove(h);
|
public override bool Remove(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Remove(h);
|
||||||
|
|
||||||
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
|
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
|
||||||
|
|
||||||
@ -86,6 +86,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the total amount of columns across all stages in this playfield.
|
||||||
|
/// </summary>
|
||||||
|
public int TotalColumns => stages.Sum(s => s.Columns.Count);
|
||||||
|
|
||||||
private ManiaStage getStageByColumn(int column)
|
private ManiaStage getStageByColumn(int column)
|
||||||
{
|
{
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
@ -156,18 +156,29 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public override void Add(DrawableHitObject h)
|
public override void Add(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
var maniaObject = (ManiaHitObject)h.HitObject;
|
var maniaObject = (ManiaHitObject)h.HitObject;
|
||||||
int columnIndex = maniaObject.Column - firstColumnIndex;
|
|
||||||
Columns.ElementAt(columnIndex).Add(h);
|
int columnIndex = -1;
|
||||||
|
|
||||||
|
maniaObject.ColumnBindable.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
if (columnIndex != -1)
|
||||||
|
Columns.ElementAt(columnIndex).Remove(h);
|
||||||
|
|
||||||
|
columnIndex = maniaObject.Column - firstColumnIndex;
|
||||||
|
Columns.ElementAt(columnIndex).Add(h);
|
||||||
|
}, true);
|
||||||
|
|
||||||
h.OnNewResult += OnNewResult;
|
h.OnNewResult += OnNewResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Remove(DrawableHitObject h)
|
public override bool Remove(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
var maniaObject = (ManiaHitObject)h.HitObject;
|
var maniaObject = (ManiaHitObject)h.HitObject;
|
||||||
int columnIndex = maniaObject.Column - firstColumnIndex;
|
int columnIndex = maniaObject.Column - firstColumnIndex;
|
||||||
Columns.ElementAt(columnIndex).Remove(h);
|
Columns.ElementAt(columnIndex).Remove(h);
|
||||||
|
|
||||||
h.OnNewResult -= OnNewResult;
|
h.OnNewResult -= OnNewResult;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -16,7 +15,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
|||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AdjustPosition(DragEvent dragEvent) => OsuObject.Position += dragEvent.Delta;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
@ -10,13 +9,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
{
|
{
|
||||||
public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint
|
public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint
|
||||||
{
|
{
|
||||||
private readonly Slider slider;
|
|
||||||
|
|
||||||
public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position)
|
public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
this.slider = slider;
|
|
||||||
|
|
||||||
InternalChild = new SliderCirclePiece(slider, position);
|
InternalChild = new SliderCirclePiece(slider, position);
|
||||||
|
|
||||||
Select();
|
Select();
|
||||||
@ -24,7 +19,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
|
|
||||||
// Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input.
|
// Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input.
|
||||||
public override bool HandlePositionalInput => false;
|
public override bool HandlePositionalInput => false;
|
||||||
|
|
||||||
public override void AdjustPosition(DragEvent dragEvent) => slider.Position += dragEvent.Delta;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
@ -20,10 +19,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
public override void AdjustPosition(DragEvent dragEvent)
|
|
||||||
{
|
|
||||||
// Spinners don't support position adjustments
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Rulesets.Osu.Objects;
|
|||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
{
|
{
|
||||||
@ -35,6 +36,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new SpinnerCompositionTool()
|
new SpinnerCompositionTool()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public override SelectionHandler CreateSelectionHandler() => new OsuSelectionHandler();
|
||||||
|
|
||||||
protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both };
|
protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
|
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
|
||||||
|
30
osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
Normal file
30
osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
|
{
|
||||||
|
public class OsuSelectionHandler : SelectionHandler
|
||||||
|
{
|
||||||
|
public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent)
|
||||||
|
{
|
||||||
|
foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
|
||||||
|
{
|
||||||
|
if (h is Spinner)
|
||||||
|
{
|
||||||
|
// Spinners don't support position adjustments
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Position += dragEvent.Delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.HandleDrag(blueprint, dragEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
typeof(SelectionBox),
|
typeof(SelectionHandler),
|
||||||
typeof(DragBox),
|
typeof(DragBox),
|
||||||
typeof(HitObjectComposer),
|
typeof(HitObjectComposer),
|
||||||
typeof(OsuHitObjectComposer),
|
typeof(OsuHitObjectComposer),
|
||||||
|
@ -171,10 +171,9 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
public virtual SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null;
|
public virtual SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="SelectionBox"/> which outlines <see cref="DrawableHitObject"/>s
|
/// Creates a <see cref="SelectionHandler"/> which outlines <see cref="DrawableHitObject"/>s and handles movement of selections.
|
||||||
/// and handles hitobject pattern adjustments.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual SelectionBox CreateSelectionBox() => new SelectionBox();
|
public virtual SelectionHandler CreateSelectionHandler() => new SelectionHandler();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.
|
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when this <see cref="SelectionBlueprint"/> has requested drag.
|
/// Invoked when this <see cref="SelectionBlueprint"/> has requested drag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<DragEvent> DragRequested;
|
public event Action<SelectionBlueprint, DragEvent> DragRequested;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="DrawableHitObject"/> which this <see cref="SelectionBlueprint"/> applies to.
|
/// The <see cref="DrawableHitObject"/> which this <see cref="SelectionBlueprint"/> applies to.
|
||||||
@ -130,12 +130,10 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
protected override bool OnDrag(DragEvent e)
|
protected override bool OnDrag(DragEvent e)
|
||||||
{
|
{
|
||||||
DragRequested?.Invoke(e);
|
DragRequested?.Invoke(this, e);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void AdjustPosition(DragEvent dragEvent);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The screen-space point that causes this <see cref="SelectionBlueprint"/> to be selected.
|
/// The screen-space point that causes this <see cref="SelectionBlueprint"/> to be selected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// Remove a DrawableHitObject from this Playfield.
|
/// Remove a DrawableHitObject from this Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="h">The DrawableHitObject to remove.</param>
|
/// <param name="h">The DrawableHitObject to remove.</param>
|
||||||
public virtual void Remove(DrawableHitObject h) => HitObjectContainer.Remove(h);
|
public virtual bool Remove(DrawableHitObject h) => HitObjectContainer.Remove(h);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a <see cref="Playfield"/> as a nested <see cref="Playfield"/>.
|
/// Registers a <see cref="Playfield"/> as a nested <see cref="Playfield"/>.
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
private Container<PlacementBlueprint> placementBlueprintContainer;
|
private Container<PlacementBlueprint> placementBlueprintContainer;
|
||||||
private PlacementBlueprint currentPlacement;
|
private PlacementBlueprint currentPlacement;
|
||||||
|
|
||||||
private SelectionBox selectionBox;
|
private SelectionHandler selectionHandler;
|
||||||
|
|
||||||
private IEnumerable<SelectionBlueprint> selections => selectionBlueprints.Children.Where(c => c.IsAlive);
|
private IEnumerable<SelectionBlueprint> selections => selectionBlueprints.Children.Where(c => c.IsAlive);
|
||||||
|
|
||||||
@ -37,16 +37,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
selectionBox = composer.CreateSelectionBox();
|
selectionHandler = composer.CreateSelectionHandler();
|
||||||
selectionBox.DeselectAll = deselectAll;
|
selectionHandler.DeselectAll = deselectAll;
|
||||||
|
|
||||||
var dragBox = new DragBox(select);
|
var dragBox = new DragBox(select);
|
||||||
dragBox.DragEnd += () => selectionBox.UpdateVisibility();
|
dragBox.DragEnd += () => selectionHandler.UpdateVisibility();
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
dragBox,
|
dragBox,
|
||||||
selectionBox,
|
selectionHandler,
|
||||||
selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both },
|
selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both },
|
||||||
placementBlueprintContainer = new Container<PlacementBlueprint> { RelativeSizeAxes = Axes.Both },
|
placementBlueprintContainer = new Container<PlacementBlueprint> { RelativeSizeAxes = Axes.Both },
|
||||||
dragBox.CreateProxy()
|
dragBox.CreateProxy()
|
||||||
@ -168,19 +168,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
private void onBlueprintSelected(SelectionBlueprint blueprint)
|
private void onBlueprintSelected(SelectionBlueprint blueprint)
|
||||||
{
|
{
|
||||||
selectionBox.HandleSelected(blueprint);
|
selectionHandler.HandleSelected(blueprint);
|
||||||
selectionBlueprints.ChangeChildDepth(blueprint, 1);
|
selectionBlueprints.ChangeChildDepth(blueprint, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBlueprintDeselected(SelectionBlueprint blueprint)
|
private void onBlueprintDeselected(SelectionBlueprint blueprint)
|
||||||
{
|
{
|
||||||
selectionBox.HandleDeselected(blueprint);
|
selectionHandler.HandleDeselected(blueprint);
|
||||||
selectionBlueprints.ChangeChildDepth(blueprint, 0);
|
selectionBlueprints.ChangeChildDepth(blueprint, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSelectionRequested(SelectionBlueprint blueprint, InputState state) => selectionBox.HandleSelectionRequested(blueprint, state);
|
private void onSelectionRequested(SelectionBlueprint blueprint, InputState state) => selectionHandler.HandleSelectionRequested(blueprint, state);
|
||||||
|
|
||||||
private void onDragRequested(DragEvent dragEvent) => selectionBox.HandleDrag(dragEvent);
|
private void onDragRequested(SelectionBlueprint blueprint, DragEvent dragEvent) => selectionHandler.HandleDrag(blueprint, dragEvent);
|
||||||
|
|
||||||
private class SelectionBlueprintContainer : Container<SelectionBlueprint>
|
private class SelectionBlueprintContainer : Container<SelectionBlueprint>
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
BorderColour = Color4.White,
|
BorderColour = Color4.White,
|
||||||
BorderThickness = SelectionBox.BORDER_RADIUS,
|
BorderThickness = SelectionHandler.BORDER_RADIUS,
|
||||||
Child = new Box
|
Child = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
@ -12,26 +12,31 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Framework.Input.States;
|
using osu.Framework.Input.States;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components
|
namespace osu.Game.Screens.Edit.Compose.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A box which surrounds <see cref="SelectionBlueprint"/>s and provides interactive handles, context menus etc.
|
/// A component which outlines <see cref="DrawableHitObject"/>s and handles movement of selections.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SelectionBox : CompositeDrawable
|
public class SelectionHandler : CompositeDrawable
|
||||||
{
|
{
|
||||||
public const float BORDER_RADIUS = 2;
|
public const float BORDER_RADIUS = 2;
|
||||||
|
|
||||||
|
protected IEnumerable<SelectionBlueprint> SelectedBlueprints => selectedBlueprints;
|
||||||
private readonly List<SelectionBlueprint> selectedBlueprints;
|
private readonly List<SelectionBlueprint> selectedBlueprints;
|
||||||
|
|
||||||
|
protected IEnumerable<HitObject> SelectedHitObjects => selectedBlueprints.Select(b => b.HitObject.HitObject);
|
||||||
|
|
||||||
private Drawable outline;
|
private Drawable outline;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IPlacementHandler placementHandler { get; set; }
|
private IPlacementHandler placementHandler { get; set; }
|
||||||
|
|
||||||
public SelectionBox()
|
public SelectionHandler()
|
||||||
{
|
{
|
||||||
selectedBlueprints = new List<SelectionBlueprint>();
|
selectedBlueprints = new List<SelectionBlueprint>();
|
||||||
|
|
||||||
@ -59,12 +64,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
#region User Input Handling
|
#region User Input Handling
|
||||||
|
|
||||||
public void HandleDrag(DragEvent dragEvent)
|
/// <summary>
|
||||||
|
/// Handles the selected <see cref="DrawableHitObject"/>s being dragged.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blueprint">The <see cref="SelectionBlueprint"/> that received the drag event.</param>
|
||||||
|
/// <param name="dragEvent">The drag event.</param>
|
||||||
|
public virtual void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent)
|
||||||
{
|
{
|
||||||
// Todo: Various forms of snapping
|
|
||||||
|
|
||||||
foreach (var blueprint in selectedBlueprints)
|
|
||||||
blueprint.AdjustPosition(dragEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
@ -90,19 +96,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bind an action to deselect all selected blueprints.
|
/// Bind an action to deselect all selected blueprints.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action DeselectAll { private get; set; }
|
internal Action DeselectAll { private get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle a blueprint becoming selected.
|
/// Handle a blueprint becoming selected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="blueprint">The blueprint.</param>
|
/// <param name="blueprint">The blueprint.</param>
|
||||||
public void HandleSelected(SelectionBlueprint blueprint) => selectedBlueprints.Add(blueprint);
|
internal void HandleSelected(SelectionBlueprint blueprint) => selectedBlueprints.Add(blueprint);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle a blueprint becoming deselected.
|
/// Handle a blueprint becoming deselected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="blueprint">The blueprint.</param>
|
/// <param name="blueprint">The blueprint.</param>
|
||||||
public void HandleDeselected(SelectionBlueprint blueprint)
|
internal void HandleDeselected(SelectionBlueprint blueprint)
|
||||||
{
|
{
|
||||||
selectedBlueprints.Remove(blueprint);
|
selectedBlueprints.Remove(blueprint);
|
||||||
|
|
||||||
@ -115,7 +121,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// Handle a blueprint requesting selection.
|
/// Handle a blueprint requesting selection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="blueprint">The blueprint.</param>
|
/// <param name="blueprint">The blueprint.</param>
|
||||||
public void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state)
|
internal void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state)
|
||||||
{
|
{
|
||||||
if (state.Keyboard.ControlPressed)
|
if (state.Keyboard.ControlPressed)
|
||||||
{
|
{
|
||||||
@ -139,7 +145,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates whether this <see cref="SelectionBox"/> is visible.
|
/// Updates whether this <see cref="SelectionHandler"/> is visible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void UpdateVisibility()
|
internal void UpdateVisibility()
|
||||||
{
|
{
|
Loading…
Reference in New Issue
Block a user