diff --git a/osu.Game/Localisation/EditorDialogsStrings.cs b/osu.Game/Localisation/EditorDialogsStrings.cs index 2d58dab2d77d..898ba1dbf8aa 100644 --- a/osu.Game/Localisation/EditorDialogsStrings.cs +++ b/osu.Game/Localisation/EditorDialogsStrings.cs @@ -94,6 +94,26 @@ public static class EditorDialogsStrings /// public static LocalisableString SnapAllNotesConfirmationBody => new TranslatableString(getKey(@"snap_all_notes_confirmation_body"), @"Every hit object in this difficulty will move to the nearest tick for your current snap divisor. Slider and hold durations may change. You can undo this from the editor history."); + /// + /// "Sync to all difficulties?" + /// + public static LocalisableString SyncTimingConfirmationHeader => new TranslatableString(getKey(@"sync_timing_confirmation_header"), @"Sync to all difficulties?"); + + /// + /// "This overwrites the selected options on all other difficulties. This cannot be undone." + /// + public static LocalisableString SyncTimingConfirmationBody => new TranslatableString(getKey(@"sync_timing_confirmation_body"), @"This overwrites the selected options on all other difficulties. This cannot be undone."); + + /// + /// "Bookmarks" + /// + public static LocalisableString SyncTimingOptionBookmarks => new TranslatableString(getKey(@"sync_timing_option_bookmarks"), @"Bookmarks"); + + /// + /// "Preview point" + /// + public static LocalisableString SyncTimingOptionPreviewPoint => new TranslatableString(getKey(@"sync_timing_option_preview_point"), @"Preview point"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 5d3fae0ea775..e21eca1e3274 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -309,6 +309,11 @@ public static class EditorStrings /// public static LocalisableString SampleSet => new TranslatableString(getKey(@"sample_set"), @"Sample set"); + /// + /// "Sync to all difficulties" + /// + public static LocalisableString SyncToAllDifficulties => new TranslatableString(getKey(@"sync_to_all_difficulties"), @"Sync to all difficulties"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 862cd1fa7b10..0bdc420eb69e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -451,6 +451,10 @@ private void load(OsuConfigManager config) Items = new MenuItem[] { new EditorMenuItem(EditorStrings.SetPreviewPointToCurrent, MenuItemType.Standard, SetPreviewPointToCurrentTime), + new EditorMenuItem(EditorStrings.SyncToAllDifficulties, MenuItemType.Destructive, confirmSyncTimingToAllDifficulties) + { + Action = { Disabled = loadableBeatmap.BeatmapSetInfo.Beatmaps.Count < 2 } + }, new EditorMenuItem(EditorStrings.SnapAllNotesToCurrentSnapDivisor, MenuItemType.Destructive, confirmSnapAllHitObjectsToCurrentDivisor), bookmarkController.Menu, } @@ -1037,6 +1041,52 @@ protected void SetPreviewPointToCurrentTime() editorBeatmap.PreviewTime.Value = (int)clock.CurrentTime; } + private void confirmSyncTimingToAllDifficulties() + { + dialogOverlay.Push(new SyncTimingConfirmationDialog(syncTimingToAllOtherDifficulties)); + } + + private void syncTimingToAllOtherDifficulties(bool syncBookmarks, bool syncPreviewPoint) + { + if (Beatmap.Value.BeatmapSetInfo.Beatmaps.Count <= 1) + return; + + if (!syncBookmarks && !syncPreviewPoint) + return; + + var set = Beatmap.Value.BeatmapSetInfo; + var current = editorBeatmap.BeatmapInfo; + int[] sourceBookmarks = editorBeatmap.Bookmarks.ToArray(); + int sourcePreviewTime = editorBeatmap.BeatmapInfo.Metadata.PreviewTime; + + foreach (var beatmapInfo in set.Beatmaps) + { + if (beatmapInfo.Equals(current)) + continue; + + try + { + var targetWorking = beatmapManager.GetWorkingBeatmap(beatmapInfo); + var playable = targetWorking.GetPlayableBeatmap(beatmapInfo.Ruleset); + + if (syncBookmarks) + playable.Bookmarks = sourceBookmarks.ToArray(); + + if (syncPreviewPoint) + beatmapInfo.Metadata.PreviewTime = sourcePreviewTime; + + beatmapManager.Save(beatmapInfo, playable, targetWorking.GetSkin(), targetWorking.Storyboard); + } + catch (Exception e) + { + Logger.Error(e, $@"Failed to sync bookmarks/preview to {beatmapInfo.GetDisplayTitle()}"); + return; + } + } + + SaveAndReload(withDialog: false); + } + private void confirmSnapAllHitObjectsToCurrentDivisor() { dialogOverlay.Push(new SnapAllNotesConfirmationDialog(SnapAllHitObjectsToCurrentDivisor)); diff --git a/osu.Game/Screens/Edit/SyncTimingConfirmationDialog.cs b/osu.Game/Screens/Edit/SyncTimingConfirmationDialog.cs new file mode 100644 index 000000000000..ecbaea3679b0 --- /dev/null +++ b/osu.Game/Screens/Edit/SyncTimingConfirmationDialog.cs @@ -0,0 +1,52 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; +using osuTK; + +namespace osu.Game.Screens.Edit +{ + public partial class SyncTimingConfirmationDialog : DangerousActionDialog + { + private readonly BindableBool syncBookmarks = new BindableBool(true); + private readonly BindableBool syncPreviewPoint = new BindableBool(true); + + public SyncTimingConfirmationDialog(Action syncAction) + { + HeaderText = EditorDialogsStrings.SyncTimingConfirmationHeader; + BodyText = EditorDialogsStrings.SyncTimingConfirmationBody; + + DangerousAction = () => syncAction(syncBookmarks.Value, syncPreviewPoint.Value); + + MainContent.Child = new FillFlowContainer + { + Margin = new MarginPadding { Top = 20 }, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 400, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new OsuCheckbox + { + LabelText = EditorDialogsStrings.SyncTimingOptionBookmarks, + Current = { BindTarget = syncBookmarks }, + }, + new OsuCheckbox + { + LabelText = EditorDialogsStrings.SyncTimingOptionPreviewPoint, + Current = { BindTarget = syncPreviewPoint }, + }, + } + }; + } + } +}