1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-12 14:19:34 +08:00
osu-lazer/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs

184 lines
6.1 KiB
C#
Raw Normal View History

// 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 osu.Framework.Allocation;
2019-10-31 15:23:54 +08:00
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects;
2018-11-20 15:51:59 +08:00
using osuTK;
2019-10-31 15:23:54 +08:00
using osuTK.Graphics;
2018-11-07 15:08:56 +08:00
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
public class PathControlPointPiece : BlueprintPiece<Slider>
{
2019-10-31 16:13:10 +08:00
public Action<int> RequestSelection;
public Action<Vector2[]> ControlPointsChanged;
2019-10-31 16:13:10 +08:00
public readonly Bindable<bool> IsSelected = new Bindable<bool>();
2019-10-31 15:23:54 +08:00
public readonly int Index;
2019-10-31 15:23:54 +08:00
private readonly Slider slider;
private readonly Path path;
2019-10-31 15:23:54 +08:00
private readonly Container marker;
private readonly Drawable markerRing;
2019-10-31 16:13:10 +08:00
private bool isClicked;
[Resolved]
private OsuColour colours { get; set; }
public PathControlPointPiece(Slider slider, int index)
{
this.slider = slider;
2019-10-31 15:23:54 +08:00
Index = index;
Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
path = new SmoothPath
{
Anchor = Anchor.Centre,
2019-03-07 16:39:19 +08:00
PathRadius = 1
},
2019-10-31 15:23:54 +08:00
marker = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
2019-10-31 15:23:54 +08:00
AutoSizeAxes = Axes.Both,
Children = new[]
{
new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(10),
},
markerRing = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(14),
Masking = true,
BorderThickness = 2,
BorderColour = Color4.White,
Alpha = 0,
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
}
}
};
}
protected override void Update()
{
base.Update();
2019-10-31 15:23:54 +08:00
Position = slider.StackedPosition + slider.Path.ControlPoints[Index];
updateMarkerDisplay();
updateConnectingPath();
}
/// <summary>
/// Updates the state of the circular control point marker.
/// </summary>
private void updateMarkerDisplay()
{
markerRing.Alpha = IsSelected.Value ? 1 : 0;
2019-10-31 15:23:54 +08:00
Color4 colour = isSegmentSeparator ? colours.Red : colours.Yellow;
2019-10-31 16:13:10 +08:00
if (IsHovered || isClicked || IsSelected.Value)
2019-10-31 15:23:54 +08:00
colour = Color4.White;
marker.Colour = colour;
}
2019-10-31 15:23:54 +08:00
/// <summary>
/// Updates the path connecting this control point to the previous one.
/// </summary>
private void updateConnectingPath()
{
path.ClearVertices();
2019-10-31 15:23:54 +08:00
if (Index != slider.Path.ControlPoints.Length - 1)
{
path.AddVertex(Vector2.Zero);
2019-10-31 15:23:54 +08:00
path.AddVertex(slider.Path.ControlPoints[Index + 1] - slider.Path.ControlPoints[Index]);
}
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
}
2019-10-31 15:23:54 +08:00
// The connecting path is excluded from positional input
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => marker.ReceivePositionalInputAt(screenSpacePos);
2019-10-31 16:13:10 +08:00
protected override bool OnMouseDown(MouseDownEvent e)
{
isClicked = true;
return true;
}
protected override bool OnMouseUp(MouseUpEvent e)
{
isClicked = false;
return true;
}
protected override bool OnClick(ClickEvent e)
{
RequestSelection?.Invoke(Index);
return true;
}
protected override bool OnDragStart(DragStartEvent e) => true;
protected override bool OnDrag(DragEvent e)
{
var newControlPoints = slider.Path.ControlPoints.ToArray();
2019-10-31 15:23:54 +08:00
if (Index == 0)
{
// Special handling for the head - only the position of the slider changes
slider.Position += e.Delta;
// Since control points are relative to the position of the slider, they all need to be offset backwards by the delta
for (int i = 1; i < newControlPoints.Length; i++)
newControlPoints[i] -= e.Delta;
}
else
2019-10-31 15:23:54 +08:00
newControlPoints[Index] += e.Delta;
if (isSegmentSeparatorWithNext)
2019-10-31 15:23:54 +08:00
newControlPoints[Index + 1] = newControlPoints[Index];
if (isSegmentSeparatorWithPrevious)
2019-10-31 15:23:54 +08:00
newControlPoints[Index - 1] = newControlPoints[Index];
ControlPointsChanged?.Invoke(newControlPoints);
return true;
}
protected override bool OnDragEnd(DragEndEvent e) => true;
private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious;
2018-10-29 14:52:28 +08:00
2019-10-31 15:23:54 +08:00
private bool isSegmentSeparatorWithNext => Index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[Index + 1] == slider.Path.ControlPoints[Index];
2018-10-29 14:52:28 +08:00
2019-10-31 15:23:54 +08:00
private bool isSegmentSeparatorWithPrevious => Index > 0 && slider.Path.ControlPoints[Index - 1] == slider.Path.ControlPoints[Index];
}
}