diff --git a/osu.Game/Screens/Edit/ClipboardContent.cs b/osu.Game/Screens/Edit/ClipboardContent.cs new file mode 100644 index 0000000000..b2edbedccc --- /dev/null +++ b/osu.Game/Screens/Edit/ClipboardContent.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using osu.Game.IO.Serialization; +using osu.Game.IO.Serialization.Converters; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Edit +{ + public class ClipboardContent : IJsonSerializable + { + [JsonConverter(typeof(TypedListConverter))] + public IList HitObjects; + + public ClipboardContent() + { + } + + public ClipboardContent(EditorBeatmap editorBeatmap) + { + HitObjects = editorBeatmap.SelectedHitObjects.ToList(); + } + } +} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 23eb704920..a063b0a303 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -22,6 +23,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; +using osu.Game.IO.Serialization; using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Rulesets.Edit; @@ -131,9 +133,14 @@ namespace osu.Game.Screens.Edit updateLastSavedHash(); EditorMenuBar menuBar; + OsuMenuItem undoMenuItem; OsuMenuItem redoMenuItem; + EditorMenuItem cutMenuItem; + EditorMenuItem copyMenuItem; + EditorMenuItem pasteMenuItem; + var fileMenuItems = new List { new EditorMenuItem("Save", MenuItemType.Standard, Save) @@ -183,7 +190,11 @@ namespace osu.Game.Screens.Edit Items = new[] { undoMenuItem = new EditorMenuItem("Undo", MenuItemType.Standard, Undo), - redoMenuItem = new EditorMenuItem("Redo", MenuItemType.Standard, Redo) + redoMenuItem = new EditorMenuItem("Redo", MenuItemType.Standard, Redo), + new EditorMenuItemSpacer(), + cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut), + copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy), + pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste), } } } @@ -244,6 +255,17 @@ 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); + // todo: BindCollectionChanged + editorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => + { + var hasObjects = editorBeatmap.SelectedHitObjects.Count > 0; + + cutMenuItem.Action.Disabled = !hasObjects; + copyMenuItem.Action.Disabled = !hasObjects; + }; + + clipboard.BindValueChanged(content => pasteMenuItem.Action.Disabled = string.IsNullOrEmpty(content.NewValue)); + menuBar.Mode.ValueChanged += onModeChanged; bottomBackground.Colour = colours.Gray2; @@ -394,6 +416,34 @@ namespace osu.Game.Screens.Edit this.Exit(); } + private readonly Bindable clipboard = new Bindable(); + + protected void Cut() + { + Copy(); + foreach (var h in editorBeatmap.SelectedHitObjects.ToArray()) + editorBeatmap.Remove(h); + } + + protected void Copy() + { + clipboard.Value = new ClipboardContent(editorBeatmap).Serialize(); + } + + protected void Paste() + { + if (string.IsNullOrEmpty(clipboard.Value)) + return; + + var objects = clipboard.Value.Deserialize().HitObjects; + double timeOffset = clock.CurrentTime - objects.First().StartTime; + + foreach (var h in objects) + h.StartTime += timeOffset; + + editorBeatmap.AddRange(objects); + } + protected void Undo() => changeHandler.RestoreState(-1); protected void Redo() => changeHandler.RestoreState(1);