1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-30 06:12:58 +08:00

Implement direct choice of slider control point path type via Alt-number

This commit is contained in:
Bartłomiej Dach 2024-06-17 18:33:36 +02:00
parent a631d245da
commit 683d5310b1
No known key found for this signature in database
2 changed files with 91 additions and 46 deletions

View File

@ -245,40 +245,73 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
}
// ReSharper disable once StaticMemberInGenericType
private static readonly PathType?[] path_types =
[
null,
PathType.LINEAR,
PathType.BEZIER,
PathType.PERFECT_CURVE,
PathType.BSpline(4),
];
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Repeat || e.Key != Key.Tab)
if (e.Repeat)
return false;
var selectedPieces = Pieces.Where(p => p.IsSelected.Value).ToArray();
if (selectedPieces.Length != 1)
return false;
var selectedPoint = selectedPieces.Single().ControlPoint;
var validTypes = getValidPathTypes(selectedPoint).ToArray();
int currentTypeIndex = Array.IndexOf(validTypes, selectedPoint.Type);
var selectedPiece = selectedPieces.Single();
var selectedPoint = selectedPiece.ControlPoint;
if (currentTypeIndex < 0 && e.ShiftPressed)
currentTypeIndex = 0;
do
switch (e.Key)
{
currentTypeIndex = (validTypes.Length + currentTypeIndex + (e.ShiftPressed ? -1 : 1)) % validTypes.Length;
selectedPoint.Type = validTypes[currentTypeIndex];
EnsureValidPathTypes();
} while (selectedPoint.Type != validTypes[currentTypeIndex]);
case Key.Tab:
{
var validTypes = path_types;
return true;
if (selectedPoint == controlPoints[0])
validTypes = validTypes.Where(t => t != null).ToArray();
IEnumerable<PathType?> getValidPathTypes(PathControlPoint pathControlPoint)
{
if (pathControlPoint != controlPoints[0])
yield return null;
int currentTypeIndex = Array.IndexOf(validTypes, selectedPoint.Type);
yield return PathType.LINEAR;
yield return PathType.BEZIER;
yield return PathType.PERFECT_CURVE;
yield return PathType.BSpline(4);
if (currentTypeIndex < 0 && e.ShiftPressed)
currentTypeIndex = 0;
changeHandler?.BeginChange();
do
{
currentTypeIndex = (validTypes.Length + currentTypeIndex + (e.ShiftPressed ? -1 : 1)) % validTypes.Length;
updatePathTypeOfSelectedPieces(validTypes[currentTypeIndex]);
} while (selectedPoint.Type != validTypes[currentTypeIndex]);
changeHandler?.EndChange();
return true;
}
case Key.Number0:
case Key.Number1:
case Key.Number2:
case Key.Number3:
case Key.Number4:
{
var type = path_types[e.Key - Key.Number0];
if (selectedPoint == controlPoints[0] && type == null)
return false;
updatePathTypeOfSelectedPieces(type);
return true;
}
default:
return false;
}
}
@ -291,30 +324,38 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
}
/// <summary>
/// Attempts to set the given control point piece to the given path type.
/// Attempts to set all selected control point pieces to the given path type.
/// If that would fail, try to change the path such that it instead succeeds
/// in a UX-friendly way.
/// </summary>
/// <param name="piece">The control point piece that we want to change the path type of.</param>
/// <param name="type">The path type we want to assign to the given control point piece.</param>
private void updatePathType(PathControlPointPiece<T> piece, PathType? type)
private void updatePathTypeOfSelectedPieces(PathType? type)
{
var pointsInSegment = hitObject.Path.PointsInSegment(piece.ControlPoint);
int indexInSegment = pointsInSegment.IndexOf(piece.ControlPoint);
changeHandler?.BeginChange();
if (type?.Type == SplineType.PerfectCurve)
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
{
// Can't always create a circular arc out of 4 or more points,
// so we split the segment into one 3-point circular arc segment
// and one segment of the previous type.
int thirdPointIndex = indexInSegment + 2;
var pointsInSegment = hitObject.Path.PointsInSegment(p.ControlPoint);
int indexInSegment = pointsInSegment.IndexOf(p.ControlPoint);
if (pointsInSegment.Count > thirdPointIndex + 1)
pointsInSegment[thirdPointIndex].Type = pointsInSegment[0].Type;
if (type?.Type == SplineType.PerfectCurve)
{
// Can't always create a circular arc out of 4 or more points,
// so we split the segment into one 3-point circular arc segment
// and one segment of the previous type.
int thirdPointIndex = indexInSegment + 2;
if (pointsInSegment.Count > thirdPointIndex + 1)
pointsInSegment[thirdPointIndex].Type = pointsInSegment[0].Type;
}
hitObject.Path.ExpectedDistance.Value = null;
p.ControlPoint.Type = type;
}
hitObject.Path.ExpectedDistance.Value = null;
piece.ControlPoint.Type = type;
EnsureValidPathTypes();
changeHandler?.EndChange();
}
[Resolved(CanBeNull = true)]
@ -470,17 +511,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
int totalCount = Pieces.Count(p => p.IsSelected.Value);
int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type == type);
var item = new TernaryStateRadioMenuItem(type?.Description ?? "Inherit", MenuItemType.Standard, _ =>
{
changeHandler?.BeginChange();
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
updatePathType(p, type);
EnsureValidPathTypes();
changeHandler?.EndChange();
});
var item = new TernaryStateRadioMenuItem(type?.Description ?? "Inherit", MenuItemType.Standard, _ => updatePathTypeOfSelectedPieces(type));
if (countOfState == totalCount)
item.State.Value = TernaryState.True;

View File

@ -253,6 +253,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
return true;
}
case Key.Number1:
case Key.Number2:
case Key.Number3:
case Key.Number4:
{
if (!e.AltPressed)
return false;
usingCustomSegmentType = true;
segmentStart.Type = path_types[e.Key - Key.Number1];
controlPointVisualiser.EnsureValidPathTypes();
return true;
}
case Key.Tab:
{
usingCustomSegmentType = true;