mirror of
https://github.com/ppy/osu.git
synced 2025-03-10 03:57:20 +08:00
Add "discard unsaved changes" operation to beatmap editor
Apparently useful in modding workflows when you want to test out a few different variants of a thing. Re-uses `Ctrl-L` binding from stable. Some folks may argue that the dialog makes the hotkey pointless, but I really do want to protect users from accidental data loss, and also if you want to power through it quickly, you can hit the 1 key when the dialog shows, which will bypass the hold-to-activate period (which wasn't intentional, but so many people want a bypass at this point that we're probably keeping that behaviour for power users).
This commit is contained in:
parent
f6cf63edae
commit
3f461c0734
@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
{
|
||||
keyCount.Current.Value = 8;
|
||||
});
|
||||
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<ReloadEditorDialog>);
|
||||
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
|
||||
AddStep("refuse", () => InputManager.Key(Key.Number2));
|
||||
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
|
||||
|
||||
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
{
|
||||
keyCount.Current.Value = 8;
|
||||
});
|
||||
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().Single().CurrentDialog, Is.InstanceOf<ReloadEditorDialog>);
|
||||
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().Single().CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
|
||||
AddStep("acquiesce", () => InputManager.Key(Key.Number1));
|
||||
AddUntilStep("beatmap became 8K", () => Game.Beatmap.Value.BeatmapInfo.Difficulty.CircleSize, () => Is.EqualTo(8));
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
|
||||
|
||||
updatingKeyCount = true;
|
||||
|
||||
editor.Reload().ContinueWith(t =>
|
||||
editor.SaveAndReload().ContinueWith(t =>
|
||||
{
|
||||
if (!t.GetResultSafely())
|
||||
{
|
||||
|
@ -155,6 +155,7 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.B }, GlobalAction.EditorRemoveClosestBookmark),
|
||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Left }, GlobalAction.EditorSeekToPreviousBookmark),
|
||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Right }, GlobalAction.EditorSeekToNextBookmark),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.L }, GlobalAction.EditorDiscardUnsavedChanges),
|
||||
};
|
||||
|
||||
private static IEnumerable<KeyBinding> editorTestPlayKeyBindings => new[]
|
||||
@ -502,6 +503,9 @@ namespace osu.Game.Input.Bindings
|
||||
|
||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorToggleMoveControl))]
|
||||
EditorToggleMoveControl,
|
||||
|
||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorDiscardUnsavedChanges))]
|
||||
EditorDiscardUnsavedChanges,
|
||||
}
|
||||
|
||||
public enum GlobalActionCategory
|
||||
|
@ -54,6 +54,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString EditorReloadDialogHeader => new TranslatableString(getKey(@"editor_reload_dialog_header"), @"The editor must be reloaded to apply this change. The beatmap will be saved.");
|
||||
|
||||
/// <summary>
|
||||
/// "Discard all unsaved changes? This cannot be undone."
|
||||
/// </summary>
|
||||
public static LocalisableString DiscardUnsavedChangesDialogHeader => new TranslatableString(getKey(@"discard_unsaved_changes_dialog_header"), @"Discard all unsaved changes? This cannot be undone.");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
@ -459,6 +459,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString EditorToggleMoveControl => new TranslatableString(getKey(@"editor_toggle_move_control"), @"Toggle movement control");
|
||||
|
||||
/// <summary>
|
||||
/// "Discard unsaved changes"
|
||||
/// </summary>
|
||||
public static LocalisableString EditorDiscardUnsavedChanges => new TranslatableString(getKey(@"editor_discard_unsaved_changes"), @"Discard unsaved changes");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
33
osu.Game/Screens/Edit/DiscardUnsavedChangesDialog.cs
Normal file
33
osu.Game/Screens/Edit/DiscardUnsavedChangesDialog.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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 osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Screens.Edit
|
||||
{
|
||||
public partial class DiscardUnsavedChangesDialog : PopupDialog
|
||||
{
|
||||
public DiscardUnsavedChangesDialog(Action exit)
|
||||
{
|
||||
HeaderText = EditorDialogsStrings.DiscardUnsavedChangesDialogHeader;
|
||||
|
||||
Icon = FontAwesome.Solid.Trash;
|
||||
|
||||
Buttons = new PopupDialogButton[]
|
||||
{
|
||||
new PopupDialogDangerousButton
|
||||
{
|
||||
Text = EditorDialogsStrings.ForgetAllChanges,
|
||||
Action = exit
|
||||
},
|
||||
new PopupDialogCancelButton
|
||||
{
|
||||
Text = EditorDialogsStrings.ContinueEditing,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -164,6 +164,7 @@ namespace osu.Game.Screens.Edit
|
||||
private bool switchingDifficulty;
|
||||
|
||||
private string lastSavedHash;
|
||||
private EditorMenuItem discardChangesMenuItem;
|
||||
|
||||
private ScreenContainer screenContainer;
|
||||
|
||||
@ -391,6 +392,10 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
undoMenuItem = new EditorMenuItem(CommonStrings.Undo, MenuItemType.Standard, Undo) { Hotkey = new Hotkey(PlatformAction.Undo) },
|
||||
redoMenuItem = new EditorMenuItem(CommonStrings.Redo, MenuItemType.Standard, Redo) { Hotkey = new Hotkey(PlatformAction.Redo) },
|
||||
discardChangesMenuItem = new EditorMenuItem("Discard unsaved changes", MenuItemType.Destructive, DiscardUnsavedChanges)
|
||||
{
|
||||
Hotkey = new Hotkey(GlobalAction.EditorDiscardUnsavedChanges)
|
||||
},
|
||||
new OsuMenuItemSpacer(),
|
||||
cutMenuItem = new EditorMenuItem(CommonStrings.Cut, MenuItemType.Standard, Cut) { Hotkey = new Hotkey(PlatformAction.Cut) },
|
||||
copyMenuItem = new EditorMenuItem(CommonStrings.Copy, MenuItemType.Standard, Copy) { Hotkey = new Hotkey(PlatformAction.Copy) },
|
||||
@ -607,6 +612,8 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
base.Update();
|
||||
clock.ProcessFrame();
|
||||
|
||||
discardChangesMenuItem.Action.Disabled = !HasUnsavedChanges;
|
||||
}
|
||||
|
||||
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
||||
@ -821,6 +828,10 @@ namespace osu.Game.Screens.Edit
|
||||
case GlobalAction.EditorTestGameplay:
|
||||
bottomBar.TestGameplayButton.TriggerClick();
|
||||
return true;
|
||||
|
||||
case GlobalAction.EditorDiscardUnsavedChanges:
|
||||
DiscardUnsavedChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1008,6 +1019,20 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
protected void Redo() => changeHandler?.RestoreState(1);
|
||||
|
||||
protected void DiscardUnsavedChanges()
|
||||
{
|
||||
if (!HasUnsavedChanges)
|
||||
return;
|
||||
|
||||
// we're not doing this via `changeHandler` because `changeHandler` has limited number of undo actions
|
||||
// and therefore there's no guarantee that it even *has* the beatmap's last saved state in its history still.
|
||||
dialogOverlay.Push(new DiscardUnsavedChangesDialog(() =>
|
||||
{
|
||||
updateLastSavedHash(); // without this a second dialog will show (the standard "save unsaved changes" one that shows on exit).
|
||||
SwitchToDifficulty(editorBeatmap.BeatmapInfo);
|
||||
}));
|
||||
}
|
||||
|
||||
protected void SetPreviewPointToCurrentTime()
|
||||
{
|
||||
editorBeatmap.PreviewTime.Value = (int)clock.CurrentTime;
|
||||
@ -1510,11 +1535,11 @@ namespace osu.Game.Screens.Edit
|
||||
loader?.CancelPendingDifficultySwitch();
|
||||
}
|
||||
|
||||
public Task<bool> Reload()
|
||||
public Task<bool> SaveAndReload()
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
|
||||
dialogOverlay.Push(new ReloadEditorDialog(
|
||||
dialogOverlay.Push(new SaveAndReloadEditorDialog(
|
||||
reload: () =>
|
||||
{
|
||||
bool reloadedSuccessfully = attemptMutationOperation(() =>
|
||||
|
@ -8,9 +8,9 @@ using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Screens.Edit
|
||||
{
|
||||
public partial class ReloadEditorDialog : PopupDialog
|
||||
public partial class SaveAndReloadEditorDialog : PopupDialog
|
||||
{
|
||||
public ReloadEditorDialog(Action reload, Action cancel)
|
||||
public SaveAndReloadEditorDialog(Action reload, Action cancel)
|
||||
{
|
||||
HeaderText = EditorDialogsStrings.EditorReloadDialogHeader;
|
||||
|
Loading…
x
Reference in New Issue
Block a user