mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 10:23:20 +08:00
Add EditorCommandHandler
This commit is contained in:
parent
b658d9a681
commit
b2276fbee7
14
osu.Game/Screens/Edit/Commands/IEditorCommand.cs
Normal file
14
osu.Game/Screens/Edit/Commands/IEditorCommand.cs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
namespace osu.Game.Screens.Edit.Commands
|
||||
{
|
||||
public interface IEditorCommand
|
||||
{
|
||||
public void Apply();
|
||||
|
||||
public IEditorCommand CreateUndo();
|
||||
|
||||
public virtual bool IsRedundant => false;
|
||||
}
|
||||
}
|
@ -179,6 +179,8 @@ namespace osu.Game.Screens.Edit
|
||||
[CanBeNull] // Should be non-null once it can support custom rulesets.
|
||||
private EditorChangeHandler changeHandler;
|
||||
|
||||
private EditorCommandHandler commandHandler;
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
private bool isNewBeatmap;
|
||||
@ -300,6 +302,9 @@ namespace osu.Game.Screens.Edit
|
||||
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
|
||||
}
|
||||
|
||||
commandHandler = new EditorCommandHandler();
|
||||
dependencies.CacheAs(commandHandler);
|
||||
|
||||
beatDivisor.SetArbitraryDivisor(editorBeatmap.BeatmapInfo.BeatDivisor);
|
||||
beatDivisor.BindValueChanged(divisor => editorBeatmap.BeatmapInfo.BeatDivisor = divisor.NewValue);
|
||||
|
||||
@ -428,8 +433,8 @@ namespace osu.Game.Screens.Edit
|
||||
}
|
||||
});
|
||||
|
||||
changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
|
||||
changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true);
|
||||
commandHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
|
||||
commandHandler.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true);
|
||||
|
||||
editorBackgroundDim.BindValueChanged(_ => dimBackground());
|
||||
}
|
||||
@ -964,9 +969,9 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
#endregion
|
||||
|
||||
protected void Undo() => changeHandler?.RestoreState(-1);
|
||||
protected void Undo() => commandHandler.Undo();
|
||||
|
||||
protected void Redo() => changeHandler?.RestoreState(1);
|
||||
protected void Redo() => commandHandler.Redo();
|
||||
|
||||
protected void SetPreviewPointToCurrentTime()
|
||||
{
|
||||
|
154
osu.Game/Screens/Edit/EditorCommandHandler.cs
Normal file
154
osu.Game/Screens/Edit/EditorCommandHandler.cs
Normal file
@ -0,0 +1,154 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Edit.Commands;
|
||||
|
||||
namespace osu.Game.Screens.Edit
|
||||
{
|
||||
public partial class EditorCommandHandler : Component
|
||||
{
|
||||
public EditorCommandHandler()
|
||||
{
|
||||
}
|
||||
|
||||
public event Action<IEditorCommand>? CommandApplied;
|
||||
|
||||
public readonly Bindable<bool> CanUndo = new BindableBool();
|
||||
|
||||
public readonly Bindable<bool> CanRedo = new BindableBool();
|
||||
|
||||
public bool HasUncommittedChanges => currentTransaction.Entries.Count != 0;
|
||||
|
||||
public void Submit(IEditorCommand command, bool commitImmediately = false)
|
||||
{
|
||||
if (command.IsRedundant)
|
||||
return;
|
||||
|
||||
record(command);
|
||||
apply(command);
|
||||
|
||||
if (commitImmediately)
|
||||
Commit();
|
||||
}
|
||||
|
||||
public void Submit(IEnumerable<IEditorCommand> commands, bool commitImmediately = false)
|
||||
{
|
||||
foreach (var command in commands)
|
||||
Submit(command);
|
||||
|
||||
if (commitImmediately)
|
||||
Commit();
|
||||
}
|
||||
|
||||
public bool Commit()
|
||||
{
|
||||
if (!HasUncommittedChanges)
|
||||
return false;
|
||||
|
||||
undoStack.Push(currentTransaction);
|
||||
redoStack.Clear();
|
||||
|
||||
currentTransaction = new Transaction();
|
||||
|
||||
historyChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Undo()
|
||||
{
|
||||
if (undoStack.Count == 0)
|
||||
return false;
|
||||
|
||||
var transaction = undoStack.Pop();
|
||||
|
||||
revertTransaction(transaction);
|
||||
|
||||
redoStack.Push(transaction);
|
||||
|
||||
historyChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Redo()
|
||||
{
|
||||
if (redoStack.Count == 0)
|
||||
return false;
|
||||
|
||||
var transaction = redoStack.Pop();
|
||||
|
||||
foreach (var entry in transaction.Entries)
|
||||
apply(entry.Command);
|
||||
|
||||
undoStack.Push(transaction);
|
||||
|
||||
historyChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RevertUncommitedChanges()
|
||||
{
|
||||
if (!HasUncommittedChanges)
|
||||
return false;
|
||||
|
||||
revertTransaction(currentTransaction);
|
||||
|
||||
currentTransaction = new Transaction();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void revertTransaction(Transaction transaction)
|
||||
{
|
||||
foreach (var entry in transaction.Entries.Reverse())
|
||||
apply(entry.Reverse);
|
||||
}
|
||||
|
||||
private void historyChanged()
|
||||
{
|
||||
CanUndo.Value = undoStack.Count > 0;
|
||||
CanRedo.Value = redoStack.Count > 0;
|
||||
}
|
||||
|
||||
private Transaction currentTransaction = new Transaction();
|
||||
|
||||
private readonly Stack<Transaction> undoStack = new Stack<Transaction>();
|
||||
|
||||
private readonly Stack<Transaction> redoStack = new Stack<Transaction>();
|
||||
|
||||
private void apply(IEditorCommand command)
|
||||
{
|
||||
command.Apply();
|
||||
CommandApplied?.Invoke(command);
|
||||
}
|
||||
|
||||
private void record(IEditorCommand command)
|
||||
{
|
||||
var reverse = command.CreateUndo();
|
||||
|
||||
currentTransaction.Add(new HistoryEntry(command, reverse));
|
||||
}
|
||||
|
||||
private readonly record struct HistoryEntry(IEditorCommand Command, IEditorCommand Reverse);
|
||||
|
||||
private readonly struct Transaction
|
||||
{
|
||||
public Transaction()
|
||||
{
|
||||
}
|
||||
|
||||
private readonly List<HistoryEntry> entries = new List<HistoryEntry>();
|
||||
|
||||
public IReadOnlyList<HistoryEntry> Entries => entries;
|
||||
|
||||
public void Add(HistoryEntry entry) => entries.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user