1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 00:42:55 +08:00

Merge pull request #24059 from peppy/add-editor-rotate-hotkeys

Add support for `Ctrl` + `<` / `>` to rotate selection in editor
This commit is contained in:
Dean Herbert 2023-06-28 12:03:34 +09:00 committed by GitHub
commit 076f41be12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 35 deletions

View File

@ -101,6 +101,38 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("objects reverted to original position", () => addedObjects[0].StartTime == 100); AddAssert("objects reverted to original position", () => addedObjects[0].StartTime == 100);
} }
[Test]
public void TestRotateHotkeys()
{
HitCircle[] addedObjects = null;
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
{
new HitCircle { StartTime = 100 },
new HitCircle { StartTime = 200, Position = new Vector2(100) },
new HitCircle { StartTime = 300, Position = new Vector2(200) },
new HitCircle { StartTime = 400, Position = new Vector2(300) },
}));
AddStep("select objects", () => EditorBeatmap.SelectedHitObjects.AddRange(addedObjects));
AddStep("rotate clockwise", () =>
{
InputManager.PressKey(Key.ControlLeft);
InputManager.Key(Key.Period);
InputManager.ReleaseKey(Key.ControlLeft);
});
AddAssert("objects rotated clockwise", () => addedObjects[0].Position == new Vector2(300, 0));
AddStep("rotate counterclockwise", () =>
{
InputManager.PressKey(Key.ControlLeft);
InputManager.Key(Key.Comma);
InputManager.ReleaseKey(Key.ControlLeft);
});
AddAssert("objects reverted to original position", () => addedObjects[0].Position == new Vector2(0));
}
[Test] [Test]
public void TestBasicSelect() public void TestBasicSelect()
{ {

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -24,13 +22,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
private const float button_padding = 5; private const float button_padding = 5;
public Func<float, bool> OnRotation; public Func<float, bool>? OnRotation;
public Func<Vector2, Anchor, bool> OnScale; public Func<Vector2, Anchor, bool>? OnScale;
public Func<Direction, bool, bool> OnFlip; public Func<Direction, bool, bool>? OnFlip;
public Func<bool> OnReverse; public Func<bool>? OnReverse;
public Action OperationStarted; public Action? OperationStarted;
public Action OperationEnded; public Action? OperationEnded;
private SelectionBoxButton? reverseButton;
private SelectionBoxButton? rotateClockwiseButton;
private SelectionBoxButton? rotateCounterClockwiseButton;
private bool canReverse; private bool canReverse;
@ -134,7 +136,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
} }
} }
private string text; private string text = string.Empty;
public string Text public string Text
{ {
@ -150,13 +152,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
} }
} }
private SelectionBoxDragHandleContainer dragHandles; private SelectionBoxDragHandleContainer dragHandles = null!;
private FillFlowContainer buttons; private FillFlowContainer buttons = null!;
private OsuSpriteText selectionDetailsText; private OsuSpriteText? selectionDetailsText;
[Resolved] [Resolved]
private OsuColour colours { get; set; } private OsuColour colours { get; set; } = null!;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() => recreate(); private void load() => recreate();
@ -166,19 +168,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (e.Repeat || !e.ControlPressed) if (e.Repeat || !e.ControlPressed)
return false; return false;
bool runOperationFromHotkey(Func<bool> operation)
{
operationStarted();
bool result = operation?.Invoke() ?? false;
operationEnded();
return result;
}
switch (e.Key) switch (e.Key)
{ {
case Key.G: case Key.G:
return CanReverse && runOperationFromHotkey(OnReverse); return CanReverse && reverseButton?.TriggerClick() == true;
case Key.Comma:
return CanRotate && rotateCounterClockwiseButton?.TriggerClick() == true;
case Key.Period:
return CanRotate && rotateClockwiseButton?.TriggerClick() == true;
} }
return base.OnKeyDown(e); return base.OnKeyDown(e);
@ -256,13 +255,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (CanFlipX) addXFlipComponents(); if (CanFlipX) addXFlipComponents();
if (CanFlipY) addYFlipComponents(); if (CanFlipY) addYFlipComponents();
if (CanRotate) addRotationComponents(); if (CanRotate) addRotationComponents();
if (CanReverse) addButton(FontAwesome.Solid.Backward, "Reverse pattern (Ctrl-G)", () => OnReverse?.Invoke()); if (CanReverse) reverseButton = addButton(FontAwesome.Solid.Backward, "Reverse pattern (Ctrl-G)", () => OnReverse?.Invoke());
} }
private void addRotationComponents() private void addRotationComponents()
{ {
addButton(FontAwesome.Solid.Undo, "Rotate 90 degrees counter-clockwise", () => OnRotation?.Invoke(-90)); rotateCounterClockwiseButton = addButton(FontAwesome.Solid.Undo, "Rotate 90 degrees counter-clockwise (Ctrl-<)", () => OnRotation?.Invoke(-90));
addButton(FontAwesome.Solid.Redo, "Rotate 90 degrees clockwise", () => OnRotation?.Invoke(90)); rotateClockwiseButton = addButton(FontAwesome.Solid.Redo, "Rotate 90 degrees clockwise (Ctrl->)", () => OnRotation?.Invoke(90));
addRotateHandle(Anchor.TopLeft); addRotateHandle(Anchor.TopLeft);
addRotateHandle(Anchor.TopRight); addRotateHandle(Anchor.TopRight);
@ -300,7 +299,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false)); addButton(FontAwesome.Solid.ArrowsAltV, "Flip vertically", () => OnFlip?.Invoke(Direction.Vertical, false));
} }
private void addButton(IconUsage icon, string tooltip, Action action) private SelectionBoxButton addButton(IconUsage icon, string tooltip, Action action)
{ {
var button = new SelectionBoxButton(icon, tooltip) var button = new SelectionBoxButton(icon, tooltip)
{ {
@ -310,6 +309,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
button.OperationStarted += operationStarted; button.OperationStarted += operationStarted;
button.OperationEnded += operationEnded; button.OperationEnded += operationEnded;
buttons.Add(button); buttons.Add(button);
return button;
} }
private void addScaleHandle(Anchor anchor) private void addScaleHandle(Anchor anchor)

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -17,11 +15,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
{ {
public sealed partial class SelectionBoxButton : SelectionBoxControl, IHasTooltip public sealed partial class SelectionBoxButton : SelectionBoxControl, IHasTooltip
{ {
private SpriteIcon icon; private SpriteIcon icon = null!;
private readonly IconUsage iconUsage; private readonly IconUsage iconUsage;
public Action Action; public Action? Action;
public SelectionBoxButton(IconUsage iconUsage, string tooltip) public SelectionBoxButton(IconUsage iconUsage, string tooltip)
{ {
@ -49,6 +47,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnClick(ClickEvent e) protected override bool OnClick(ClickEvent e)
{ {
Circle.FlashColour(Colours.GrayF, 300);
TriggerOperationStarted(); TriggerOperationStarted();
Action?.Invoke(); Action?.Invoke();
TriggerOperationEnded(); TriggerOperationEnded();

View File

@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
public event Action OperationStarted; public event Action OperationStarted;
public event Action OperationEnded; public event Action OperationEnded;
private Circle circle; protected Circle Circle { get; private set; }
/// <summary> /// <summary>
/// Whether the user is currently holding the control with mouse. /// Whether the user is currently holding the control with mouse.
@ -41,7 +41,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
circle = new Circle Circle = new Circle
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -85,9 +85,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected virtual void UpdateHoverState() protected virtual void UpdateHoverState()
{ {
if (IsHeld) if (IsHeld)
circle.FadeColour(Colours.GrayF, TRANSFORM_DURATION, Easing.OutQuint); Circle.FadeColour(Colours.GrayF, TRANSFORM_DURATION, Easing.OutQuint);
else else
circle.FadeColour(IsHovered ? Colours.Red : Colours.YellowDark, TRANSFORM_DURATION, Easing.OutQuint); Circle.FadeColour(IsHovered ? Colours.Red : Colours.YellowDark, TRANSFORM_DURATION, Easing.OutQuint);
this.ScaleTo(IsHeld || IsHovered ? 1.5f : 1, TRANSFORM_DURATION, Easing.OutQuint); this.ScaleTo(IsHeld || IsHovered ? 1.5f : 1, TRANSFORM_DURATION, Easing.OutQuint);
} }