1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-11 15:27:20 +08:00

Merge pull request #20828 from peppy/grid-momentary-shortcuts

Add momentary shortcuts to toggle grid/distance snap
This commit is contained in:
Bartłomiej Dach 2022-10-26 22:04:32 +02:00 committed by GitHub
commit 5c4ff87d07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 21 deletions

View File

@ -10,7 +10,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -23,7 +22,6 @@ using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Components.TernaryButtons;
using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components;
using osuTK; using osuTK;
@ -35,8 +33,6 @@ namespace osu.Game.Rulesets.Catch.Edit
private CatchDistanceSnapGrid distanceSnapGrid; private CatchDistanceSnapGrid distanceSnapGrid;
private readonly Bindable<TernaryState> distanceSnapToggle = new Bindable<TernaryState>();
private InputManager inputManager; private InputManager inputManager;
private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1) private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1)
@ -120,11 +116,6 @@ namespace osu.Game.Rulesets.Catch.Edit
new BananaShowerCompositionTool() new BananaShowerCompositionTool()
}; };
protected override IEnumerable<TernaryButton> CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[]
{
new TernaryButton(distanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler })
});
public override SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) public override SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All)
{ {
var result = base.FindSnappedPositionAndTime(screenSpacePosition, snapType); var result = base.FindSnappedPositionAndTime(screenSpacePosition, snapType);
@ -196,7 +187,7 @@ namespace osu.Game.Rulesets.Catch.Edit
private void updateDistanceSnapGrid() private void updateDistanceSnapGrid()
{ {
if (distanceSnapToggle.Value != TernaryState.True) if (DistanceSnapToggle.Value != TernaryState.True)
{ {
distanceSnapGrid.Hide(); distanceSnapGrid.Hide();
return; return;

View File

@ -44,6 +44,28 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
rectangularGridActive(false); rectangularGridActive(false);
} }
[Test]
public void TestDistanceSnapMomentaryToggle()
{
AddStep("select second object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.ElementAt(1)));
AddUntilStep("distance snap grid hidden", () => !this.ChildrenOfType<OsuDistanceSnapGrid>().Any());
AddStep("hold alt", () => InputManager.PressKey(Key.AltLeft));
AddUntilStep("distance snap grid visible", () => this.ChildrenOfType<OsuDistanceSnapGrid>().Any());
AddStep("release alt", () => InputManager.ReleaseKey(Key.AltLeft));
AddUntilStep("distance snap grid hidden", () => !this.ChildrenOfType<OsuDistanceSnapGrid>().Any());
}
[Test]
public void TestGridSnapMomentaryToggle()
{
rectangularGridActive(false);
AddStep("hold shift", () => InputManager.PressKey(Key.ShiftLeft));
rectangularGridActive(true);
AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft));
rectangularGridActive(false);
}
private void rectangularGridActive(bool active) private void rectangularGridActive(bool active)
{ {
AddStep("choose placement tool", () => InputManager.Key(Key.Number2)); AddStep("choose placement tool", () => InputManager.Key(Key.Number2));
@ -57,8 +79,6 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
AddAssert("placement blueprint at (0, 0)", () => Precision.AlmostEquals(Editor.ChildrenOfType<HitCirclePlacementBlueprint>().Single().HitObject.Position, new Vector2(0, 0))); AddAssert("placement blueprint at (0, 0)", () => Precision.AlmostEquals(Editor.ChildrenOfType<HitCirclePlacementBlueprint>().Single().HitObject.Position, new Vector2(0, 0)));
else else
AddAssert("placement blueprint at (1, 1)", () => Precision.AlmostEquals(Editor.ChildrenOfType<HitCirclePlacementBlueprint>().Single().HitObject.Position, new Vector2(1, 1))); AddAssert("placement blueprint at (1, 1)", () => Precision.AlmostEquals(Editor.ChildrenOfType<HitCirclePlacementBlueprint>().Single().HitObject.Position, new Vector2(1, 1)));
AddStep("choose selection tool", () => InputManager.Key(Key.Number1));
} }
[Test] [Test]

View File

@ -13,8 +13,10 @@ using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -44,12 +46,10 @@ namespace osu.Game.Rulesets.Osu.Edit
new SpinnerCompositionTool() new SpinnerCompositionTool()
}; };
private readonly Bindable<TernaryState> distanceSnapToggle = new Bindable<TernaryState>();
private readonly Bindable<TernaryState> rectangularGridSnapToggle = new Bindable<TernaryState>(); private readonly Bindable<TernaryState> rectangularGridSnapToggle = new Bindable<TernaryState>();
protected override IEnumerable<TernaryButton> CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[] protected override IEnumerable<TernaryButton> CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[]
{ {
new TernaryButton(distanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler }),
new TernaryButton(rectangularGridSnapToggle, "Grid Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Th }) new TernaryButton(rectangularGridSnapToggle, "Grid Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Th })
}); });
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Edit
placementObject = EditorBeatmap.PlacementObject.GetBoundCopy(); placementObject = EditorBeatmap.PlacementObject.GetBoundCopy();
placementObject.ValueChanged += _ => updateDistanceSnapGrid(); placementObject.ValueChanged += _ => updateDistanceSnapGrid();
distanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid(); DistanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid();
// we may be entering the screen with a selection already active // we may be entering the screen with a selection already active
updateDistanceSnapGrid(); updateDistanceSnapGrid();
@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Edit
if (snapType.HasFlagFast(SnapType.Grids)) if (snapType.HasFlagFast(SnapType.Grids))
{ {
if (distanceSnapToggle.Value == TernaryState.True && distanceSnapGrid != null) if (DistanceSnapToggle.Value == TernaryState.True && distanceSnapGrid != null)
{ {
(Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition)); (Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition));
@ -195,7 +195,7 @@ namespace osu.Game.Rulesets.Osu.Edit
distanceSnapGridCache.Invalidate(); distanceSnapGridCache.Invalidate();
distanceSnapGrid = null; distanceSnapGrid = null;
if (distanceSnapToggle.Value != TernaryState.True) if (DistanceSnapToggle.Value != TernaryState.True)
return; return;
switch (BlueprintContainer.CurrentTool) switch (BlueprintContainer.CurrentTool)
@ -222,6 +222,42 @@ namespace osu.Game.Rulesets.Osu.Edit
} }
} }
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Repeat)
return false;
handleToggleViaKey(e);
return base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyUpEvent e)
{
handleToggleViaKey(e);
base.OnKeyUp(e);
}
protected override bool AdjustDistanceSpacing(GlobalAction action, float amount)
{
// To allow better visualisation, ensure that the spacing grid is visible before adjusting.
DistanceSnapToggle.Value = TernaryState.True;
return base.AdjustDistanceSpacing(action, amount);
}
private bool gridSnapMomentary;
private void handleToggleViaKey(KeyboardEvent key)
{
bool shiftPressed = key.ShiftPressed;
if (shiftPressed != gridSnapMomentary)
{
gridSnapMomentary = shiftPressed;
rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False;
}
}
private DistanceSnapGrid createDistanceSnapGrid(IEnumerable<HitObject> selectedHitObjects) private DistanceSnapGrid createDistanceSnapGrid(IEnumerable<HitObject> selectedHitObjects)
{ {
if (BlueprintContainer.CurrentTool is SpinnerCompositionTool) if (BlueprintContainer.CurrentTool is SpinnerCompositionTool)

View File

@ -161,10 +161,11 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("hold alt", () => InputManager.PressKey(Key.LAlt)); AddStep("hold alt", () => InputManager.PressKey(Key.LAlt));
AddStep("scroll mouse 5 steps", () => InputManager.ScrollVerticalBy(5)); AddStep("scroll mouse 5 steps", () => InputManager.ScrollVerticalBy(5));
AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5);
AddStep("release alt", () => InputManager.ReleaseKey(Key.LAlt)); AddStep("release alt", () => InputManager.ReleaseKey(Key.LAlt));
AddStep("release ctrl", () => InputManager.ReleaseKey(Key.LControl)); AddStep("release ctrl", () => InputManager.ReleaseKey(Key.LControl));
AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5);
} }
public class EditorBeatmapContainer : Container public class EditorBeatmapContainer : Container

View File

@ -3,6 +3,8 @@
#nullable disable #nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
@ -10,6 +12,7 @@ using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
@ -20,6 +23,7 @@ using osu.Game.Overlays;
using osu.Game.Overlays.OSD; using osu.Game.Overlays.OSD;
using osu.Game.Overlays.Settings.Sections; using osu.Game.Overlays.Settings.Sections;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit.Components.TernaryButtons;
namespace osu.Game.Rulesets.Edit namespace osu.Game.Rulesets.Edit
{ {
@ -48,6 +52,10 @@ namespace osu.Game.Rulesets.Edit
[Resolved(canBeNull: true)] [Resolved(canBeNull: true)]
private OnScreenDisplay onScreenDisplay { get; set; } private OnScreenDisplay onScreenDisplay { get; set; }
protected readonly Bindable<TernaryState> DistanceSnapToggle = new Bindable<TernaryState>();
private bool distanceSnapMomentary;
protected DistancedHitObjectComposer(Ruleset ruleset) protected DistancedHitObjectComposer(Ruleset ruleset)
: base(ruleset) : base(ruleset)
{ {
@ -105,13 +113,44 @@ namespace osu.Game.Rulesets.Edit
} }
} }
protected override IEnumerable<TernaryButton> CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[]
{
new TernaryButton(DistanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler })
});
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Repeat)
return false;
handleToggleViaKey(e);
return base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyUpEvent e)
{
handleToggleViaKey(e);
base.OnKeyUp(e);
}
private void handleToggleViaKey(KeyboardEvent key)
{
bool altPressed = key.AltPressed;
if (altPressed != distanceSnapMomentary)
{
distanceSnapMomentary = altPressed;
DistanceSnapToggle.Value = DistanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False;
}
}
public virtual bool OnPressed(KeyBindingPressEvent<GlobalAction> e) public virtual bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{ {
switch (e.Action) switch (e.Action)
{ {
case GlobalAction.EditorIncreaseDistanceSpacing: case GlobalAction.EditorIncreaseDistanceSpacing:
case GlobalAction.EditorDecreaseDistanceSpacing: case GlobalAction.EditorDecreaseDistanceSpacing:
return adjustDistanceSpacing(e.Action, adjust_step); return AdjustDistanceSpacing(e.Action, adjust_step);
} }
return false; return false;
@ -127,13 +166,13 @@ namespace osu.Game.Rulesets.Edit
{ {
case GlobalAction.EditorIncreaseDistanceSpacing: case GlobalAction.EditorIncreaseDistanceSpacing:
case GlobalAction.EditorDecreaseDistanceSpacing: case GlobalAction.EditorDecreaseDistanceSpacing:
return adjustDistanceSpacing(e.Action, e.ScrollAmount * adjust_step); return AdjustDistanceSpacing(e.Action, e.ScrollAmount * adjust_step);
} }
return false; return false;
} }
private bool adjustDistanceSpacing(GlobalAction action, float amount) protected virtual bool AdjustDistanceSpacing(GlobalAction action, float amount)
{ {
if (DistanceSpacingMultiplier.Disabled) if (DistanceSpacingMultiplier.Disabled)
return false; return false;