Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hotkey hints to editor menus #29691

Merged
merged 10 commits into from
Oct 1, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
Expand Down Expand Up @@ -172,7 +173,10 @@ private IEnumerable<MenuItem> getContextMenuItems()
yield return new OsuMenuItem("Add vertex", MenuItemType.Standard, () =>
{
editablePath.AddVertex(rightMouseDownPosition);
});
})
{
Hotkey = new Hotkey(new KeyCombination(InputKey.Control, InputKey.MouseLeft))
};
}

protected override void Dispose(bool isDisposing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private void ensureValidPathType(IReadOnlyList<PathControlPoint> segment)
if (segment.Count == 0)
return;

var first = segment[0];
PathControlPoint first = segment[0];

if (first.Type != PathType.PERFECT_CURVE)
return;
Expand Down Expand Up @@ -273,10 +273,10 @@ protected override bool OnKeyDown(KeyDownEvent e)
if (selectedPieces.Length != 1)
return false;

var selectedPiece = selectedPieces.Single();
var selectedPoint = selectedPiece.ControlPoint;
PathControlPointPiece<T> selectedPiece = selectedPieces.Single();
PathControlPoint selectedPoint = selectedPiece.ControlPoint;

var validTypes = path_types;
PathType?[] validTypes = path_types;

if (selectedPoint == controlPoints[0])
validTypes = validTypes.Where(t => t != null).ToArray();
Expand Down Expand Up @@ -313,7 +313,7 @@ protected override bool OnKeyDown(KeyDownEvent e)
if (Pieces.All(p => !p.IsSelected.Value))
return false;

var type = path_types[e.Key - Key.Number1];
PathType? type = path_types[e.Key - Key.Number1];

// The first control point can never be inherit type
if (Pieces[0].IsSelected.Value && type == null)
Expand Down Expand Up @@ -355,7 +355,7 @@ private void updatePathTypeOfSelectedPieces(PathType? type)

foreach (var p in Pieces.Where(p => p.IsSelected.Value))
{
var pointsInSegment = hitObject.Path.PointsInSegment(p.ControlPoint);
List<PathControlPoint> pointsInSegment = hitObject.Path.PointsInSegment(p.ControlPoint);
int indexInSegment = pointsInSegment.IndexOf(p.ControlPoint);

if (type?.Type == SplineType.PerfectCurve)
Expand Down Expand Up @@ -405,14 +405,14 @@ public void DragStarted(PathControlPoint controlPoint)
public void DragInProgress(DragEvent e)
{
Vector2[] oldControlPoints = hitObject.Path.ControlPoints.Select(cp => cp.Position).ToArray();
var oldPosition = hitObject.Position;
Vector2 oldPosition = hitObject.Position;
double oldStartTime = hitObject.StartTime;

if (selectedControlPoints.Contains(hitObject.Path.ControlPoints[0]))
{
// Special handling for selections containing head control point - the position of the hit object changes which means the snapped position and time have to be taken into account
Vector2 newHeadPosition = Parent!.ToScreenSpace(e.MousePosition + (dragStartPositions[0] - dragStartPositions[draggedControlPointIndex]));
var result = positionSnapProvider?.FindSnappedPositionAndTime(newHeadPosition);
SnapResult result = positionSnapProvider?.FindSnappedPositionAndTime(newHeadPosition);

Vector2 movementDelta = Parent!.ToLocalSpace(result?.ScreenSpacePosition ?? newHeadPosition) - hitObject.Position;

Expand All @@ -421,7 +421,7 @@ public void DragInProgress(DragEvent e)

for (int i = 1; i < hitObject.Path.ControlPoints.Count; i++)
{
var controlPoint = hitObject.Path.ControlPoints[i];
PathControlPoint controlPoint = hitObject.Path.ControlPoints[i];
// Since control points are relative to the position of the hit object, all points that are _not_ selected
// need to be offset _back_ by the delta corresponding to the movement of the head point.
// All other selected control points (if any) will move together with the head point
Expand All @@ -432,13 +432,13 @@ public void DragInProgress(DragEvent e)
}
else
{
var result = positionSnapProvider?.FindSnappedPositionAndTime(Parent!.ToScreenSpace(e.MousePosition), SnapType.GlobalGrids);
SnapResult result = positionSnapProvider?.FindSnappedPositionAndTime(Parent!.ToScreenSpace(e.MousePosition), SnapType.GlobalGrids);

Vector2 movementDelta = Parent!.ToLocalSpace(result?.ScreenSpacePosition ?? Parent!.ToScreenSpace(e.MousePosition)) - dragStartPositions[draggedControlPointIndex] - hitObject.Position;

for (int i = 0; i < controlPoints.Count; ++i)
{
var controlPoint = controlPoints[i];
PathControlPoint controlPoint = controlPoints[i];
if (selectedControlPoints.Contains(controlPoint))
controlPoint.Position = dragStartPositions[i] + movementDelta;
}
Expand Down Expand Up @@ -488,8 +488,10 @@ public MenuItem[] ContextMenuItems

curveTypeItems = new List<MenuItem>();

foreach (PathType? type in path_types)
for (int i = 0; i < path_types.Length; ++i)
{
PathType? type = path_types[i];

// special inherit case
if (type == null)
{
Expand All @@ -499,7 +501,7 @@ public MenuItem[] ContextMenuItems
curveTypeItems.Add(new OsuMenuItemSpacer());
}

curveTypeItems.Add(createMenuItemForPathType(type));
curveTypeItems.Add(createMenuItemForPathType(type, InputKey.Number1 + i));
}

if (selectedPieces.Any(piece => piece.ControlPoint.Type?.Type == SplineType.Catmull))
Expand Down Expand Up @@ -533,7 +535,15 @@ public MenuItem[] ContextMenuItems

return menuItems.ToArray();

CurveTypeMenuItem createMenuItemForPathType(PathType? type) => new CurveTypeMenuItem(type, _ => updatePathTypeOfSelectedPieces(type));
CurveTypeMenuItem createMenuItemForPathType(PathType? type, InputKey? key = null)
{
Hotkey hotkey = default;

if (key != null)
hotkey = new Hotkey(new KeyCombination(InputKey.Alt, key.Value));

return new CurveTypeMenuItem(type, _ => updatePathTypeOfSelectedPieces(type)) { Hotkey = hotkey };
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Audio;
Expand Down Expand Up @@ -593,8 +594,14 @@ private void convertToStream()
changeHandler?.BeginChange();
addControlPoint(lastRightClickPosition);
changeHandler?.EndChange();
}),
new OsuMenuItem("Convert to stream", MenuItemType.Destructive, convertToStream),
})
{
Hotkey = new Hotkey(new KeyCombination(InputKey.Control, InputKey.MouseLeft))
},
new OsuMenuItem("Convert to stream", MenuItemType.Destructive, convertToStream)
{
Hotkey = new Hotkey(new KeyCombination(InputKey.Control, InputKey.Shift, InputKey.F))
},
};

// Always refer to the drawable object's slider body so subsequent movement deltas are calculated with updated positions.
Expand Down
17 changes: 15 additions & 2 deletions osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
Expand Down Expand Up @@ -86,10 +87,22 @@ public void SetRimState(bool state)
protected override IEnumerable<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint<HitObject>> selection)
{
if (selection.All(s => s.Item is Hit))
yield return new TernaryStateToggleMenuItem("Rim") { State = { BindTarget = selectionRimState } };
{
yield return new TernaryStateToggleMenuItem("Rim")
{
State = { BindTarget = selectionRimState },
Hotkey = new Hotkey(new KeyCombination(InputKey.W), new KeyCombination(InputKey.R)),
};
}

if (selection.All(s => s.Item is TaikoHitObject))
yield return new TernaryStateToggleMenuItem("Strong") { State = { BindTarget = selectionStrongState } };
{
yield return new TernaryStateToggleMenuItem("Strong")
{
State = { BindTarget = selectionStrongState },
Hotkey = new Hotkey(new KeyCombination(InputKey.E)),
};
}

foreach (var item in base.GetContextMenuItemsForSelection(selection))
yield return item;
Expand Down
5 changes: 3 additions & 2 deletions osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.Menus;
using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Input;
Expand Down Expand Up @@ -60,7 +61,7 @@ public void TestDeleteDifficulties()
beatmapSetHashBefore = Beatmap.Value.BeatmapSetInfo.Hash;
});

AddStep("click File", () => this.ChildrenOfType<DrawableOsuMenuItem>().First().TriggerClick());
AddStep("click File", () => this.ChildrenOfType<EditorMenuBar.DrawableEditorBarMenuItem>().First().TriggerClick());

if (i == 11)
{
Expand Down Expand Up @@ -107,7 +108,7 @@ public void TestDeleteDifficultyWithPendingChanges()
EditorBeatmap.EndChange();
});

AddStep("click File", () => this.ChildrenOfType<DrawableOsuMenuItem>().First().TriggerClick());
AddStep("click File", () => this.ChildrenOfType<EditorMenuBar.DrawableEditorBarMenuItem>().First().TriggerClick());

AddStep("click delete", () => getDeleteMenuItem().TriggerClick());
AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog != null);
Expand Down
28 changes: 28 additions & 0 deletions osu.Game.Tests/Visual/UserInterface/TestSceneHotkeyDisplay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;

namespace osu.Game.Tests.Visual.UserInterface
{
public partial class TestSceneHotkeyDisplay : ThemeComparisonTestScene
{
protected override Drawable CreateContent() => new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Vertical,
Children = new[]
{
new HotkeyDisplay { Hotkey = new Hotkey(new KeyCombination(InputKey.MouseLeft)) },
new HotkeyDisplay { Hotkey = new Hotkey(GlobalAction.EditorDecreaseDistanceSpacing) },
new HotkeyDisplay { Hotkey = new Hotkey(PlatformAction.Save) },
}
};
}
}
Loading
Loading