From 8f02bd80f967db674c7d1655c3f5f72645b77c76 Mon Sep 17 00:00:00 2001 From: Terochi Date: Sun, 30 Apr 2023 16:10:59 +0200 Subject: [PATCH] Addressed changes --- .../Visual/Gameplay/TestSceneSkinEditor.cs | 29 +++++++++---- osu.Game/Overlays/SkinEditor/SkinEditor.cs | 15 ++----- .../SkinEditor/SkinEditorChangeHandler.cs | 41 +++++++++++-------- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 4a0be3bb68..f7eb42872d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -100,10 +100,15 @@ namespace osu.Game.Tests.Visual.Gameplay InputManager.PressButton(MouseButton.Left); }); - AddStep("Drag to bottom right", - () => { InputManager.MoveMouseTo(box3.ScreenSpaceDrawQuad.TopRight + new Vector2(-box3.ScreenSpaceDrawQuad.Width / 8, box3.ScreenSpaceDrawQuad.Height / 4)); }); + AddStep("Drag to bottom right", () => + { + InputManager.MoveMouseTo(box3.ScreenSpaceDrawQuad.TopRight + new Vector2(-box3.ScreenSpaceDrawQuad.Width / 8, box3.ScreenSpaceDrawQuad.Height / 4)); + }); - AddStep("Release button", () => { InputManager.ReleaseButton(MouseButton.Left); }); + AddStep("Release button", () => + { + InputManager.ReleaseButton(MouseButton.Left); + }); AddAssert("First two boxes selected", () => skinEditor.SelectedComponents, () => Is.EqualTo(new[] { box1, box2 })); @@ -113,9 +118,15 @@ namespace osu.Game.Tests.Visual.Gameplay InputManager.PressButton(MouseButton.Left); }); - AddStep("Drag to top left", () => { InputManager.MoveMouseTo(box2.ScreenSpaceDrawQuad.Centre - new Vector2(box2.ScreenSpaceDrawQuad.Width / 4)); }); + AddStep("Drag to top left", () => + { + InputManager.MoveMouseTo(box2.ScreenSpaceDrawQuad.Centre - new Vector2(box2.ScreenSpaceDrawQuad.Width / 4)); + }); - AddStep("Release button", () => { InputManager.ReleaseButton(MouseButton.Left); }); + AddStep("Release button", () => + { + InputManager.ReleaseButton(MouseButton.Left); + }); AddAssert("Last two boxes selected", () => skinEditor.SelectedComponents, () => Is.EqualTo(new[] { box2, box3 })); @@ -139,7 +150,10 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("Three black boxes added", () => targetContainer.Components.OfType().Count(), () => Is.EqualTo(3)); - AddStep("Store black box blueprints", () => { blueprints = skinEditor.ChildrenOfType().Where(b => b.Item is BigBlackBox).ToArray(); }); + AddStep("Store black box blueprints", () => + { + blueprints = skinEditor.ChildrenOfType().Where(b => b.Item is BigBlackBox).ToArray(); + }); AddAssert("Selection is black box 1", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[0].Item)); @@ -184,7 +198,6 @@ namespace osu.Game.Tests.Visual.Gameplay firstTarget = Player.ChildrenOfType().First(); changeHandler = new TestSkinEditorChangeHandler(firstTarget); - changeHandler.SaveState(); defaultState = changeHandler.GetCurrentState(); testComponents = new[] @@ -225,7 +238,7 @@ namespace osu.Game.Tests.Visual.Gameplay void revertAndCheckUnchanged() { AddStep("Revert changes", () => changeHandler.RestoreState(int.MinValue)); - AddAssert("Nothing changed", () => defaultState.SequenceEqual(changeHandler.GetCurrentState())); + AddAssert("Current state is same as default", () => defaultState.SequenceEqual(changeHandler.GetCurrentState())); } } diff --git a/osu.Game/Overlays/SkinEditor/SkinEditor.cs b/osu.Game/Overlays/SkinEditor/SkinEditor.cs index f0ad92d4da..2b23ce290f 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditor.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditor.cs @@ -235,7 +235,10 @@ namespace osu.Game.Overlays.SkinEditor }, true); canPaste.Current.BindValueChanged(paste => pasteMenuItem.Action.Disabled = !paste.NewValue, true); - SelectedComponents.BindCollectionChanged((_, _) => canCopy.Value = canCut.Value = SelectedComponents.Any(), true); + SelectedComponents.BindCollectionChanged((_, _) => + { + canCopy.Value = canCut.Value = SelectedComponents.Any(); + }, true); clipboard.Content.BindValueChanged(content => canPaste.Value = !string.IsNullOrEmpty(content.NewValue), true); @@ -342,7 +345,6 @@ namespace osu.Game.Overlays.SkinEditor changeHandler = new SkinEditorChangeHandler(skinComponentsContainer); changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); changeHandler.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); - changeHandler.SaveState(); content.Child = new SkinBlueprintContainer(skinComponentsContainer); @@ -477,18 +479,12 @@ namespace osu.Game.Overlays.SkinEditor protected void Cut() { - if (!canCut.Value) - return; - Copy(); DeleteItems(SelectedComponents.ToArray()); } protected void Copy() { - if (!canCopy.Value) - return; - clipboard.Content.Value = JsonConvert.SerializeObject(SelectedComponents.Cast().Select(s => s.CreateSerialisedInfo()).ToArray()); } @@ -504,9 +500,6 @@ namespace osu.Game.Overlays.SkinEditor protected void Paste() { - if (!canPaste.Value) - return; - changeHandler?.BeginChange(); var drawableInfo = JsonConvert.DeserializeObject(clipboard.Content.Value); diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs index 6285080d36..8c7f7bbab7 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorChangeHandler.cs @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.SkinEditor return; components = new BindableList { BindTarget = firstTarget.Components }; - components.BindCollectionChanged((_, _) => SaveState()); + components.BindCollectionChanged((_, _) => SaveState(), true); } protected override void WriteCurrentStateToStream(MemoryStream stream) @@ -61,47 +61,52 @@ namespace osu.Game.Overlays.SkinEditor ISerialisableDrawable[] targetComponents = firstTarget.Components.ToArray(); // Store components based on type for later lookup - var typedComponents = new Dictionary>(); + var typedComponents = new Dictionary>(); - foreach (var component in targetComponents) + for (int i = targetComponents.Length - 1; i >= 0; i--) { + Drawable component = (Drawable)targetComponents[i]; Type lookup = component.GetType(); - if (!typedComponents.TryGetValue(lookup, out List? typeComponents)) - typedComponents.Add(lookup, typeComponents = new List()); + if (!typedComponents.TryGetValue(lookup, out Stack? typeComponents)) + typedComponents.Add(lookup, typeComponents = new Stack()); - typeComponents.Add(component); + typeComponents.Push(component); } // Remove all components for (int i = targetComponents.Length - 1; i >= 0; i--) firstTarget.Remove(targetComponents[i], false); - // Keeps count of how many components for each type were already revived - Dictionary typedComponentCounter = typedComponents.Keys.ToDictionary(t => t, _ => 0); - foreach (var skinnableInfo in skinnableInfos) { Type lookup = skinnableInfo.Type; - if (!typedComponents.TryGetValue(lookup, out List? typeComponents)) + if (!typedComponents.TryGetValue(lookup, out Stack? typeComponents)) { firstTarget.Add((ISerialisableDrawable)skinnableInfo.CreateInstance()); continue; } - int typeComponentsUsed = typedComponentCounter[lookup]++; - - ISerialisableDrawable component; - - if (typeComponentsUsed < typeComponents.Count) + if (typeComponents.TryPop(out Drawable? component)) + { // Re-use unused component - ((Drawable)(component = typeComponents[typeComponentsUsed])).ApplySerialisedInfo(skinnableInfo); + component.ApplySerialisedInfo(skinnableInfo); + } else + { // Create new one - component = (ISerialisableDrawable)skinnableInfo.CreateInstance(); + component = skinnableInfo.CreateInstance(); + } - firstTarget.Add(component); + firstTarget.Add((ISerialisableDrawable)component); + } + + foreach ((Type _, Stack typeComponents) in typedComponents) + { + // Dispose extra components + foreach (var component in typeComponents) + component.Dispose(); } } }