diff --git a/osu.Game/Screens/Edit/BookmarkController.cs b/osu.Game/Screens/Edit/BookmarkController.cs new file mode 100644 index 0000000000..8c048ba871 --- /dev/null +++ b/osu.Game/Screens/Edit/BookmarkController.cs @@ -0,0 +1,148 @@ +// Copyright (c) ppy Pty Ltd . 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 class BookmarkController : Component, IKeyBindingHandler + { + 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 bookmarks = new BindableList(); + + 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().LastOrDefault(b => b < clock.CurrentTimeAccurate) + : bookmarks.Cast().FirstOrDefault(b => b > clock.CurrentTimeAccurate); + + if (targetBookmark != null) + clock.SeekSmoothlyTo(targetBookmark.Value); + } + + public bool OnPressed(KeyBindingPressEvent 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 e) + { + } + } +} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3302fafbb8..a5dfda9c95 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -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 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().LastOrDefault(b => b < clock.CurrentTimeAccurate) - : editorBeatmap.Bookmarks.Cast().FirstOrDefault(b => b > clock.CurrentTimeAccurate); - - if (targetBookmark != null) - clock.SeekSmoothlyTo(targetBookmark.Value); - } - private void seekSamplePoint(int direction) { double currentTime = clock.CurrentTimeAccurate;