1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 09:47:52 +08:00

Implement control point selection

This commit is contained in:
smoogipoo 2019-10-31 16:23:54 +09:00
parent 7a3ebcd0b1
commit e23a75c64a
2 changed files with 87 additions and 18 deletions

View File

@ -3,6 +3,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Lines;
@ -11,18 +12,21 @@ using osu.Framework.Input.Events;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
public class PathControlPointPiece : BlueprintPiece<Slider> public class PathControlPointPiece : BlueprintPiece<Slider>
{ {
public Action<Vector2[]> ControlPointsChanged; public Action<Vector2[]> ControlPointsChanged;
public readonly Bindable<bool> IsSelected = new Bindable<bool>();
public readonly int Index;
private readonly Slider slider; private readonly Slider slider;
private readonly int index;
private readonly Path path; private readonly Path path;
private readonly CircularContainer marker; private readonly Container marker;
private readonly Drawable markerRing;
[Resolved] [Resolved]
private OsuColour colours { get; set; } private OsuColour colours { get; set; }
@ -30,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
public PathControlPointPiece(Slider slider, int index) public PathControlPointPiece(Slider slider, int index)
{ {
this.slider = slider; this.slider = slider;
this.index = index; Index = index;
Origin = Anchor.Centre; Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
@ -42,13 +46,36 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
PathRadius = 1 PathRadius = 1
}, },
marker = new CircularContainer marker = new Container
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(10), AutoSizeAxes = Axes.Both,
Masking = true, Children = new[]
Child = new Box { RelativeSizeAxes = Axes.Both } {
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
}
}
}
} }
}; };
} }
@ -57,21 +84,42 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
base.Update(); base.Update();
Position = slider.StackedPosition + slider.Path.ControlPoints[index]; Position = slider.StackedPosition + slider.Path.ControlPoints[Index];
marker.Colour = isSegmentSeparator ? colours.Red : colours.Yellow; updateMarkerDisplay();
updateConnectingPath();
}
/// <summary>
/// Updates the state of the circular control point marker.
/// </summary>
private void updateMarkerDisplay()
{
markerRing.Alpha = IsSelected.Value ? 1 : 0;
Color4 colour = isSegmentSeparator ? colours.Red : colours.Yellow;
if (IsHovered || IsSelected.Value)
colour = Color4.White;
marker.Colour = colour;
}
/// <summary>
/// Updates the path connecting this control point to the previous one.
/// </summary>
private void updateConnectingPath()
{
path.ClearVertices(); path.ClearVertices();
if (index != slider.Path.ControlPoints.Length - 1) if (Index != slider.Path.ControlPoints.Length - 1)
{ {
path.AddVertex(Vector2.Zero); path.AddVertex(Vector2.Zero);
path.AddVertex(slider.Path.ControlPoints[index + 1] - slider.Path.ControlPoints[index]); path.AddVertex(slider.Path.ControlPoints[Index + 1] - slider.Path.ControlPoints[Index]);
} }
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
} }
// The connecting path is excluded from positional input
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => marker.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => marker.ReceivePositionalInputAt(screenSpacePos);
protected override bool OnDragStart(DragStartEvent e) => true; protected override bool OnDragStart(DragStartEvent e) => true;
@ -80,7 +128,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
var newControlPoints = slider.Path.ControlPoints.ToArray(); var newControlPoints = slider.Path.ControlPoints.ToArray();
if (index == 0) if (Index == 0)
{ {
// Special handling for the head - only the position of the slider changes // Special handling for the head - only the position of the slider changes
slider.Position += e.Delta; slider.Position += e.Delta;
@ -90,13 +138,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
newControlPoints[i] -= e.Delta; newControlPoints[i] -= e.Delta;
} }
else else
newControlPoints[index] += e.Delta; newControlPoints[Index] += e.Delta;
if (isSegmentSeparatorWithNext) if (isSegmentSeparatorWithNext)
newControlPoints[index + 1] = newControlPoints[index]; newControlPoints[Index + 1] = newControlPoints[Index];
if (isSegmentSeparatorWithPrevious) if (isSegmentSeparatorWithPrevious)
newControlPoints[index - 1] = newControlPoints[index]; newControlPoints[Index - 1] = newControlPoints[Index];
ControlPointsChanged?.Invoke(newControlPoints); ControlPointsChanged?.Invoke(newControlPoints);
@ -107,8 +155,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious;
private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[index + 1] == slider.Path.ControlPoints[index]; private bool isSegmentSeparatorWithNext => Index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[Index + 1] == slider.Path.ControlPoints[Index];
private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints[index - 1] == slider.Path.ControlPoints[index]; private bool isSegmentSeparatorWithPrevious => Index > 0 && slider.Path.ControlPoints[Index - 1] == slider.Path.ControlPoints[Index];
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osuTK; using osuTK;
@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
this.slider = slider; this.slider = slider;
RelativeSizeAxes = Axes.Both;
InternalChild = pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both }; InternalChild = pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both };
} }
@ -33,5 +36,23 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
while (slider.Path.ControlPoints.Length < pieces.Count) while (slider.Path.ControlPoints.Length < pieces.Count)
pieces.Remove(pieces[pieces.Count - 1]); pieces.Remove(pieces[pieces.Count - 1]);
} }
protected override bool OnMouseDown(MouseDownEvent e)
{
bool anySelected = false;
foreach (var piece in pieces)
{
if (piece.IsHovered)
{
piece.IsSelected.Value = true;
anySelected = true;
}
else
piece.IsSelected.Value = false;
}
return anySelected;
}
} }
} }