Fix connections hidden due to overlapping controlpoints

This commit is contained in:
smoogipoo
2020-04-13 16:13:14 +09:00
parent 886914cfe9
commit 9a65aa18d7
3 changed files with 103 additions and 34 deletions

View File

@ -0,0 +1,64 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using Humanizer;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestScenePathControlPointVisualiser : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(StringHumanizeExtensions),
typeof(PathControlPointPiece),
typeof(PathControlPointConnectionPiece)
};
private Slider slider;
private PathControlPointVisualiser visualiser;
[SetUp]
public void Setup() => Schedule(() =>
{
slider = new Slider();
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
});
[Test]
public void TestAddOverlappingControlPoints()
{
createVisualiser(true);
addControlPointStep(new Vector2(200));
addControlPointStep(new Vector2(300));
addControlPointStep(new Vector2(300));
addControlPointStep(new Vector2(500, 300));
AddAssert("last connection displayed", () =>
{
var lastConnection = visualiser.Connections.Last(c => c.ControlPoint.Position.Value == new Vector2(300));
return lastConnection.DrawWidth > 50;
});
}
private void createVisualiser(bool allowSelection) => AddStep("create visualiser", () => Child = visualiser = new PathControlPointVisualiser(slider, allowSelection)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
private void addControlPointStep(Vector2 position) => AddStep($"add control point {position}", () => slider.Path.ControlPoints.Add(new PathControlPoint(position)));
}
}

View File

@ -16,22 +16,25 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
/// </summary> /// </summary>
public class PathControlPointConnectionPiece : CompositeDrawable public class PathControlPointConnectionPiece : CompositeDrawable
{ {
public PathControlPoint ControlPoint; public readonly PathControlPoint ControlPoint;
private readonly Path path; private readonly Path path;
private readonly Slider slider; private readonly Slider slider;
private readonly int controlPointIndex;
private IBindable<Vector2> sliderPosition; private IBindable<Vector2> sliderPosition;
private IBindable<int> pathVersion; private IBindable<int> pathVersion;
public PathControlPointConnectionPiece(Slider slider, PathControlPoint controlPoint) public PathControlPointConnectionPiece(Slider slider, int controlPointIndex)
{ {
this.slider = slider; this.slider = slider;
ControlPoint = controlPoint; this.controlPointIndex = controlPointIndex;
Origin = Anchor.Centre; Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
ControlPoint = slider.Path.ControlPoints[controlPointIndex];
InternalChild = path = new SmoothPath InternalChild = path = new SmoothPath
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -61,13 +64,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
path.ClearVertices(); path.ClearVertices();
int index = slider.Path.ControlPoints.IndexOf(ControlPoint) + 1; int nextIndex = controlPointIndex + 1;
if (nextIndex == 0 || nextIndex == slider.Path.ControlPoints.Count)
if (index == 0 || index == slider.Path.ControlPoints.Count)
return; return;
path.AddVertex(Vector2.Zero); path.AddVertex(Vector2.Zero);
path.AddVertex(slider.Path.ControlPoints[index].Position.Value - ControlPoint.Position.Value); path.AddVertex(slider.Path.ControlPoints[nextIndex].Position.Value - ControlPoint.Position.Value);
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq; using System.Linq;
using Humanizer; using Humanizer;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -24,17 +25,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IHasContextMenu public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IHasContextMenu
{ {
internal readonly Container<PathControlPointPiece> Pieces; internal readonly Container<PathControlPointPiece> Pieces;
internal readonly Container<PathControlPointConnectionPiece> Connections;
private readonly Container<PathControlPointConnectionPiece> connections; private readonly IBindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
private readonly Slider slider; private readonly Slider slider;
private readonly bool allowSelection; private readonly bool allowSelection;
private InputManager inputManager; private InputManager inputManager;
private IBindableList<PathControlPoint> controlPoints;
public Action<List<PathControlPoint>> RemoveControlPointsRequested; public Action<List<PathControlPoint>> RemoveControlPointsRequested;
public PathControlPointVisualiser(Slider slider, bool allowSelection) public PathControlPointVisualiser(Slider slider, bool allowSelection)
@ -46,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
connections = new Container<PathControlPointConnectionPiece> { RelativeSizeAxes = Axes.Both }, Connections = new Container<PathControlPointConnectionPiece> { RelativeSizeAxes = Axes.Both },
Pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both } Pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both }
}; };
} }
@ -57,33 +55,38 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
inputManager = GetContainingInputManager(); inputManager = GetContainingInputManager();
controlPoints = slider.Path.ControlPoints.GetBoundCopy(); controlPoints.CollectionChanged += onControlPointsChanged;
controlPoints.ItemsAdded += addControlPoints; controlPoints.BindTo(slider.Path.ControlPoints);
controlPoints.ItemsRemoved += removeControlPoints;
addControlPoints(controlPoints);
} }
private void addControlPoints(IEnumerable<PathControlPoint> controlPoints) private void onControlPointsChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
foreach (var point in controlPoints) switch (e.Action)
{ {
Pieces.Add(new PathControlPointPiece(slider, point).With(d => case NotifyCollectionChangedAction.Add:
{ for (int i = 0; i < e.NewItems.Count; i++)
if (allowSelection) {
d.RequestSelection = selectPiece; var point = (PathControlPoint)e.NewItems[i];
}));
connections.Add(new PathControlPointConnectionPiece(slider, point)); Pieces.Add(new PathControlPointPiece(slider, point).With(d =>
} {
} if (allowSelection)
d.RequestSelection = selectPiece;
}));
private void removeControlPoints(IEnumerable<PathControlPoint> controlPoints) Connections.Add(new PathControlPointConnectionPiece(slider, e.NewStartingIndex + i));
{ }
foreach (var point in controlPoints)
{ break;
Pieces.RemoveAll(p => p.ControlPoint == point);
connections.RemoveAll(c => c.ControlPoint == point); case NotifyCollectionChangedAction.Remove:
foreach (var point in e.OldItems.Cast<PathControlPoint>())
{
Pieces.RemoveAll(p => p.ControlPoint == point);
Connections.RemoveAll(c => c.ControlPoint == point);
}
break;
} }
} }