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:
commit
076f41be12
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user