1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-11 06:37:19 +08:00

Merge pull request #31806 from bdach/bookmark-follow-ups

Improve bookmark controls
This commit is contained in:
Dean Herbert 2025-02-06 13:48:12 +09:00 committed by GitHub
commit dd53ae0e02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 155 additions and 63 deletions

View File

@ -0,0 +1,148 @@
// 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.
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Localisation;
using osu.Game.Overlays;
using osu.Game.Screens.Edit.Components.Menus;
namespace osu.Game.Screens.Edit
{
public partial class BookmarkController : Component, IKeyBindingHandler<GlobalAction>
{
public EditorMenuItem Menu { get; private set; }
[Resolved]
private EditorClock clock { get; set; } = null!;
[Resolved]
private EditorBeatmap editorBeatmap { get; set; } = null!;
[Resolved]
private IDialogOverlay? dialogOverlay { get; set; }
private readonly BindableList<int> bookmarks = new BindableList<int>();
private readonly EditorMenuItem removeBookmarkMenuItem;
private readonly EditorMenuItem seekToPreviousBookmarkMenuItem;
private readonly EditorMenuItem seekToNextBookmarkMenuItem;
private readonly EditorMenuItem resetBookmarkMenuItem;
public BookmarkController()
{
Menu = new EditorMenuItem(EditorStrings.Bookmarks)
{
Items = new MenuItem[]
{
new EditorMenuItem(EditorStrings.AddBookmark, MenuItemType.Standard, addBookmarkAtCurrentTime)
{
Hotkey = new Hotkey(GlobalAction.EditorAddBookmark),
},
removeBookmarkMenuItem = new EditorMenuItem(EditorStrings.RemoveClosestBookmark, MenuItemType.Destructive, removeClosestBookmark)
{
Hotkey = new Hotkey(GlobalAction.EditorRemoveClosestBookmark)
},
seekToPreviousBookmarkMenuItem = new EditorMenuItem(EditorStrings.SeekToPreviousBookmark, MenuItemType.Standard, () => seekBookmark(-1))
{
Hotkey = new Hotkey(GlobalAction.EditorSeekToPreviousBookmark)
},
seekToNextBookmarkMenuItem = new EditorMenuItem(EditorStrings.SeekToNextBookmark, MenuItemType.Standard, () => seekBookmark(1))
{
Hotkey = new Hotkey(GlobalAction.EditorSeekToNextBookmark)
},
resetBookmarkMenuItem = new EditorMenuItem(EditorStrings.ResetBookmarks, MenuItemType.Destructive, () => dialogOverlay?.Push(new BookmarkResetDialog(editorBeatmap)))
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
bookmarks.BindTo(editorBeatmap.Bookmarks);
}
protected override void Update()
{
base.Update();
bool hasAnyBookmark = bookmarks.Count > 0;
bool hasBookmarkCloseEnoughForDeletion = bookmarks.Any(b => Math.Abs(b - clock.CurrentTimeAccurate) < 2000);
removeBookmarkMenuItem.Action.Disabled = !hasBookmarkCloseEnoughForDeletion;
seekToPreviousBookmarkMenuItem.Action.Disabled = !hasAnyBookmark;
seekToNextBookmarkMenuItem.Action.Disabled = !hasAnyBookmark;
resetBookmarkMenuItem.Action.Disabled = !hasAnyBookmark;
}
private void addBookmarkAtCurrentTime()
{
int bookmark = (int)clock.CurrentTimeAccurate;
int idx = bookmarks.BinarySearch(bookmark);
if (idx < 0)
bookmarks.Insert(~idx, bookmark);
}
private void removeClosestBookmark()
{
if (removeBookmarkMenuItem.Action.Disabled)
return;
int closestBookmark = bookmarks.MinBy(b => Math.Abs(b - clock.CurrentTimeAccurate));
bookmarks.Remove(closestBookmark);
}
private void seekBookmark(int direction)
{
int? targetBookmark = direction < 1
? bookmarks.Cast<int?>().LastOrDefault(b => b < clock.CurrentTimeAccurate)
: bookmarks.Cast<int?>().FirstOrDefault(b => b > clock.CurrentTimeAccurate);
if (targetBookmark != null)
clock.SeekSmoothlyTo(targetBookmark.Value);
}
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{
switch (e.Action)
{
case GlobalAction.EditorSeekToPreviousBookmark:
seekBookmark(-1);
return true;
case GlobalAction.EditorSeekToNextBookmark:
seekBookmark(1);
return true;
}
if (e.Repeat)
return false;
switch (e.Action)
{
case GlobalAction.EditorAddBookmark:
addBookmarkAtCurrentTime();
return true;
case GlobalAction.EditorRemoveClosestBookmark:
removeClosestBookmark();
return true;
}
return false;
}
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}
}
}

View File

@ -317,6 +317,9 @@ namespace osu.Game.Screens.Edit
workingBeatmapUpdated = true;
});
var bookmarkController = new BookmarkController();
AddInternal(bookmarkController);
OsuMenuItem undoMenuItem;
OsuMenuItem redoMenuItem;
@ -442,29 +445,7 @@ namespace osu.Game.Screens.Edit
Items = new MenuItem[]
{
new EditorMenuItem(EditorStrings.SetPreviewPointToCurrent, MenuItemType.Standard, SetPreviewPointToCurrentTime),
new EditorMenuItem(EditorStrings.Bookmarks)
{
Items = new MenuItem[]
{
new EditorMenuItem(EditorStrings.AddBookmark, MenuItemType.Standard, addBookmarkAtCurrentTime)
{
Hotkey = new Hotkey(GlobalAction.EditorAddBookmark),
},
new EditorMenuItem(EditorStrings.RemoveClosestBookmark, MenuItemType.Destructive, removeBookmarksInProximityToCurrentTime)
{
Hotkey = new Hotkey(GlobalAction.EditorRemoveClosestBookmark)
},
new EditorMenuItem(EditorStrings.SeekToPreviousBookmark, MenuItemType.Standard, () => seekBookmark(-1))
{
Hotkey = new Hotkey(GlobalAction.EditorSeekToPreviousBookmark)
},
new EditorMenuItem(EditorStrings.SeekToNextBookmark, MenuItemType.Standard, () => seekBookmark(1))
{
Hotkey = new Hotkey(GlobalAction.EditorSeekToNextBookmark)
},
new EditorMenuItem(EditorStrings.ResetBookmarks, MenuItemType.Destructive, () => dialogOverlay?.Push(new BookmarkResetDialog(editorBeatmap)))
}
}
bookmarkController.Menu,
}
}
}
@ -800,14 +781,6 @@ namespace osu.Game.Screens.Edit
case GlobalAction.EditorSeekToNextSamplePoint:
seekSamplePoint(1);
return true;
case GlobalAction.EditorSeekToPreviousBookmark:
seekBookmark(-1);
return true;
case GlobalAction.EditorSeekToNextBookmark:
seekBookmark(1);
return true;
}
if (e.Repeat)
@ -815,14 +788,6 @@ namespace osu.Game.Screens.Edit
switch (e.Action)
{
case GlobalAction.EditorAddBookmark:
addBookmarkAtCurrentTime();
return true;
case GlobalAction.EditorRemoveClosestBookmark:
removeBookmarksInProximityToCurrentTime();
return true;
case GlobalAction.EditorCloneSelection:
Clone();
return true;
@ -855,19 +820,6 @@ namespace osu.Game.Screens.Edit
return false;
}
private void addBookmarkAtCurrentTime()
{
int bookmark = (int)clock.CurrentTimeAccurate;
int idx = editorBeatmap.Bookmarks.BinarySearch(bookmark);
if (idx < 0)
editorBeatmap.Bookmarks.Insert(~idx, bookmark);
}
private void removeBookmarksInProximityToCurrentTime()
{
editorBeatmap.Bookmarks.RemoveAll(b => Math.Abs(b - clock.CurrentTimeAccurate) < 2000);
}
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}
@ -1202,16 +1154,6 @@ namespace osu.Game.Screens.Edit
clock.SeekSmoothlyTo(found.StartTime);
}
private void seekBookmark(int direction)
{
int? targetBookmark = direction < 1
? editorBeatmap.Bookmarks.Cast<int?>().LastOrDefault(b => b < clock.CurrentTimeAccurate)
: editorBeatmap.Bookmarks.Cast<int?>().FirstOrDefault(b => b > clock.CurrentTimeAccurate);
if (targetBookmark != null)
clock.SeekSmoothlyTo(targetBookmark.Value);
}
private void seekSamplePoint(int direction)
{
double currentTime = clock.CurrentTimeAccurate;

View File

@ -115,7 +115,9 @@ namespace osu.Game.Screens.Edit
if (editorBeatmap.Bookmarks.Contains(newBookmark))
continue;
editorBeatmap.Bookmarks.Add(newBookmark);
int idx = editorBeatmap.Bookmarks.BinarySearch(newBookmark);
if (idx < 0)
editorBeatmap.Bookmarks.Insert(~idx, newBookmark);
}
}