From 683d5310b14c6b366b8b29ceaf20dffd1bcc775b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 17 Jun 2024 18:33:36 +0200 Subject: [PATCH] Implement direct choice of slider control point path type via `Alt`-number --- .../Components/PathControlPointVisualiser.cs | 123 +++++++++++------- .../Sliders/SliderPlacementBlueprint.cs | 14 ++ 2 files changed, 91 insertions(+), 46 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 2bdef4afe8..3d6e529afa 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -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 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 } /// - /// 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. /// - /// The control point piece that we want to change the path type of. /// The path type we want to assign to the given control point piece. - private void updatePathType(PathControlPointPiece 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; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index fdfb52008c..91cd270af6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -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;