diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 1c040e9dee..a5590a999d 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; @@ -52,5 +54,31 @@ namespace osu.Game.Rulesets.Osu.Edit return base.CreateBlueprintFor(hitObject); } + + protected override DistanceSnapGrid CreateDistanceSnapGrid(IEnumerable selectedHitObjects) + { + var objects = selectedHitObjects.ToList(); + + if (objects.Count == 0) + { + var lastObject = EditorBeatmap.HitObjects.LastOrDefault(h => h.StartTime < EditorClock.CurrentTime); + + if (lastObject == null) + return null; + + return new OsuDistanceSnapGrid(lastObject); + } + else + { + double minTime = objects.Min(h => h.StartTime); + + var lastObject = EditorBeatmap.HitObjects.LastOrDefault(h => h.StartTime < minTime); + + if (lastObject == null) + return null; + + return new OsuDistanceSnapGrid(lastObject); + } + } } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index bf31b76dc4..49ecea5fd0 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -33,12 +34,17 @@ namespace osu.Game.Rulesets.Edit protected EditorBeatmap EditorBeatmap { get; private set; } protected readonly Ruleset Ruleset; + [Resolved] + protected IFrameBasedClock EditorClock { get; private set; } + private IWorkingBeatmap workingBeatmap; private Beatmap playableBeatmap; private IBeatmapProcessor beatmapProcessor; private DrawableEditRulesetWrapper drawableRulesetWrapper; private BlueprintContainer blueprintContainer; + private Container distanceSnapGridContainer; + private DistanceSnapGrid distanceSnapGrid; private readonly List layerContainers = new List(); private InputManager inputManager; @@ -65,11 +71,13 @@ namespace osu.Game.Rulesets.Edit return; } - var layerBelowRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer(); - layerBelowRuleset.Child = new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }; + var layerBelowRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[] + { + distanceSnapGridContainer = new Container { RelativeSizeAxes = Axes.Both }, + new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both } + }); - var layerAboveRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer(); - layerAboveRuleset.Child = blueprintContainer = new BlueprintContainer(); + var layerAboveRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChild(blueprintContainer = new BlueprintContainer()); layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); @@ -112,11 +120,13 @@ namespace osu.Game.Rulesets.Edit }; toolboxCollection.Items = - CompositionTools.Select(t => new RadioButton(t.Name, () => blueprintContainer.CurrentTool = t)) - .Prepend(new RadioButton("Select", () => blueprintContainer.CurrentTool = null)) + CompositionTools.Select(t => new RadioButton(t.Name, () => selectTool(t))) + .Prepend(new RadioButton("Select", () => selectTool(null))) .ToList(); toolboxCollection.Items[0].Select(); + + blueprintContainer.SelectionChanged += selectionChanged; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -149,6 +159,14 @@ namespace osu.Game.Rulesets.Edit inputManager = GetContainingInputManager(); } + protected override void Update() + { + base.Update(); + + if (EditorClock.ElapsedFrameTime != 0 && blueprintContainer.CurrentTool != null) + showGridFor(Enumerable.Empty()); + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -162,6 +180,38 @@ namespace osu.Game.Rulesets.Edit }); } + private void selectionChanged(IEnumerable selectedHitObjects) + { + var hitObjects = selectedHitObjects.ToArray(); + + if (!hitObjects.Any()) + distanceSnapGridContainer.Hide(); + else + showGridFor(hitObjects); + } + + private void selectTool(HitObjectCompositionTool tool) + { + blueprintContainer.CurrentTool = tool; + + if (tool == null) + distanceSnapGridContainer.Hide(); + else + showGridFor(Enumerable.Empty()); + } + + private void showGridFor(IEnumerable selectedHitObjects) + { + distanceSnapGridContainer.Clear(); + distanceSnapGrid = CreateDistanceSnapGrid(selectedHitObjects); + + if (distanceSnapGrid != null) + { + distanceSnapGridContainer.Child = distanceSnapGrid; + distanceSnapGridContainer.Show(); + } + } + private void addHitObject(HitObject hitObject) => updateHitObject(hitObject); private void removeHitObject(HitObject hitObject) @@ -232,5 +282,13 @@ namespace osu.Game.Rulesets.Edit /// Creates a which outlines s and handles movement of selections. /// public virtual SelectionHandler CreateSelectionHandler() => new SelectionHandler(); + + /// + /// Creates the applicable for a selection. + /// + /// The selection. + /// The for . + [CanBeNull] + protected virtual DistanceSnapGrid CreateDistanceSnapGrid([NotNull] IEnumerable selectedHitObjects) => null; } }