diff --git a/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs b/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs index a2ee4a888d..695ff516b1 100644 --- a/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs +++ b/osu.Game.Rulesets.Osu/Edit/PolygonGenerationPopover.cs @@ -50,9 +50,14 @@ namespace osu.Game.Rulesets.Osu.Edit [Resolved] private HitObjectComposer composer { get; set; } = null!; + private Bindable newComboState = null!; + [BackgroundDependencyLoader] private void load() { + var selectionHandler = (EditorSelectionHandler)composer.BlueprintContainer.SelectionHandler; + newComboState = selectionHandler.SelectionNewComboState.GetBoundCopy(); + AllowableAnchors = new[] { Anchor.CentreLeft, Anchor.CentreRight }; Child = new FillFlowContainer @@ -120,10 +125,11 @@ namespace osu.Game.Rulesets.Osu.Edit changeHandler?.BeginChange(); began = true; - distanceSnapInput.Current.BindValueChanged(_ => tryCreatePolygon()); - offsetAngleInput.Current.BindValueChanged(_ => tryCreatePolygon()); - repeatCountInput.Current.BindValueChanged(_ => tryCreatePolygon()); - pointInput.Current.BindValueChanged(_ => tryCreatePolygon()); + distanceSnapInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon)); + offsetAngleInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon)); + repeatCountInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon)); + pointInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon)); + newComboState.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon)); tryCreatePolygon(); } @@ -138,39 +144,69 @@ namespace osu.Game.Rulesets.Osu.Edit double length = distanceSnapInput.Current.Value * velocity * timeSpacing; float polygonRadius = (float)(length / (2 * Math.Sin(double.Pi / pointInput.Current.Value))); - editorBeatmap.RemoveRange(insertedCircles); - insertedCircles.Clear(); + int totalPoints = pointInput.Current.Value * repeatCountInput.Current.Value; - var selectionHandler = (EditorSelectionHandler)composer.BlueprintContainer.SelectionHandler; - bool first = true; - - for (int i = 1; i <= pointInput.Current.Value * repeatCountInput.Current.Value; ++i) + if (insertedCircles.Count > totalPoints) { - float angle = float.DegreesToRadians(offsetAngleInput.Current.Value) + i * (2 * float.Pi / pointInput.Current.Value); - var position = OsuPlayfield.BASE_SIZE / 2 + new Vector2(polygonRadius * float.Cos(angle), polygonRadius * float.Sin(angle)); + editorBeatmap.RemoveRange(insertedCircles.GetRange(totalPoints, insertedCircles.Count - totalPoints)); + insertedCircles.RemoveRange(totalPoints, insertedCircles.Count - totalPoints); + } - var circle = new HitCircle + var newlyAdded = new List(); + + for (int i = 0; i < totalPoints; ++i) + { + float angle = float.DegreesToRadians(offsetAngleInput.Current.Value) + (i + 1) * (2 * float.Pi / pointInput.Current.Value); + var position = OsuPlayfield.BASE_SIZE / 2 + new Vector2(polygonRadius * float.Cos(angle), polygonRadius * float.Sin(angle)); + bool newCombo = i == 0 && newComboState.Value == TernaryState.True; + + HitCircle circle; + + if (i < insertedCircles.Count) { - Position = position, - StartTime = startTime, - NewCombo = first && selectionHandler.SelectionNewComboState.Value == TernaryState.True, - }; - // TODO: probably ensure samples also follow current ternary status (not trivial) - circle.Samples.Add(circle.CreateHitSampleInfo()); + circle = insertedCircles[i]; + + circle.Position = position; + circle.StartTime = startTime; + circle.NewCombo = newCombo; + + editorBeatmap.Update(circle); + } + else + { + circle = new HitCircle + { + Position = position, + StartTime = startTime, + NewCombo = newCombo, + }; + + newlyAdded.Add(circle); + + // TODO: probably ensure samples also follow current ternary status (not trivial) + circle.Samples.Add(circle.CreateHitSampleInfo()); + } if (position.X < 0 || position.Y < 0 || position.X > OsuPlayfield.BASE_SIZE.X || position.Y > OsuPlayfield.BASE_SIZE.Y) { commitButton.Enabled.Value = false; + editorBeatmap.RemoveRange(insertedCircles); + insertedCircles.Clear(); return; } - insertedCircles.Add(circle); startTime = beatSnapProvider.SnapTime(startTime + timeSpacing); - - first = false; } - editorBeatmap.AddRange(insertedCircles); + var previousNewComboState = newComboState.Value; + + insertedCircles.AddRange(newlyAdded); + editorBeatmap.AddRange(newlyAdded); + + // When adding new hitObjects, newCombo state will get reset to false when no objects are selected. + // Since this is the case when this popover is showing, we need to restore the previous newCombo state + newComboState.Value = previousNewComboState; + commitButton.Enabled.Value = true; } diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index ca774c34e7..a9dbfc29a9 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -258,6 +258,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private void resetTernaryStates() { + if (SelectionNewComboState.Value == TernaryState.Indeterminate) + SelectionNewComboState.Value = TernaryState.False; AutoSelectionBankEnabled.Value = true; SelectionAdditionBanksEnabled.Value = true; SelectionBankStates[HIT_BANK_AUTO].Value = TernaryState.True; @@ -269,7 +271,8 @@ namespace osu.Game.Screens.Edit.Compose.Components /// protected virtual void UpdateTernaryStates() { - SelectionNewComboState.Value = GetStateFromSelection(SelectedItems.OfType(), h => h.NewCombo); + if (SelectedItems.Any()) + SelectionNewComboState.Value = GetStateFromSelection(SelectedItems.OfType(), h => h.NewCombo); AutoSelectionBankEnabled.Value = SelectedItems.Count == 0; var samplesInSelection = SelectedItems.SelectMany(enumerateAllSamples).ToArray();