diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 2ac6e6ff22..febad0d739 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -2,11 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; using osu.Framework.Threading; using osu.Game.Screens.Play.HUD; +using osu.Game.Skinning; using osuTK; namespace osu.Game.Extensions @@ -63,5 +67,26 @@ namespace osu.Game.Extensions container.Add(child.CreateInstance()); } } + + /// + ///

A ConditionalWeakTable is preferable to a Dictionary because a Dictionary will keep + /// orphaned references to an forever, unless manually pruned.

+ ///

is used as a thin wrapper around bool because ConditionalWeakTable requires a reference type as both a key and a value.

+ ///

was chosen over because it is a common ancestor between (which is required for logic) + /// and (which is required for serialization via ).

+ ///

This collection is thread-safe according to the + /// documentation, + /// but the BindableBools are not unless leased.

+ ///
+ private static readonly ConditionalWeakTable is_drawable_using_closest_anchor_lookup = new ConditionalWeakTable(); + + /// + /// Gets or creates a representing whether is using the closest anchor point within its + /// parent. + /// + /// A whose is if the is using the closest anchor point, + /// otherwise . + public static BindableBool IsUsingClosestAnchor(this IDrawable drawable) => + is_drawable_using_closest_anchor_lookup.GetValue(drawable, _ => new BindableBool(true)); } } diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index fbe7cc6d91..5619a7ba19 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.CompilerServices; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; @@ -22,23 +20,6 @@ namespace osu.Game.Skinning.Editor { public class SkinSelectionHandler : SelectionHandler { - /// - ///

Keeps track of whether a is using the closest anchor point within its parent, - /// or whether the user is overriding its anchor point.

- ///

Each key is either a direct cast of an Anchor value, or it is equal to . This is done - /// because the "Closest" menu item is not a valid anchor, so something other than an anchor must be used.

- ///

Each value is a . If the is , the user has - /// overridden the anchor point. - /// If , the closest anchor point is assigned to the Drawable when it is either dragged by the user via , or when "Closest" is assigned from - /// the anchor context menu via .

- ///
- /// - ///

A ConditionalWeakTable is preferable to a Dictionary because a Dictionary will keep - /// orphaned references to a Drawable forever, unless manually pruned

- ///

is used as a thin wrapper around bool because ConditionalWeakTable requires a reference type as both a key and a value.

- ///
- private readonly ConditionalWeakTable isDrawableUsingClosestAnchorLookup = new ConditionalWeakTable(); - private const string closest_text = @"Closest"; /// @@ -118,9 +99,6 @@ namespace osu.Game.Skinning.Editor return result; } - /// Defaults to , meaning anchors are closest by default. - private BindableBool isDrawableUsingClosestAnchor(Drawable drawable) => isDrawableUsingClosestAnchorLookup.GetValue(drawable, _ => new BindableBool(true)); - [Resolved] private SkinEditor skinEditor { get; set; } @@ -261,7 +239,7 @@ namespace osu.Game.Skinning.Editor private void updateDrawableAnchorIfUsingClosest(Drawable drawable) { - if (!isDrawableUsingClosestAnchor(drawable).Value) return; + if (!drawable.IsUsingClosestAnchor().Value) return; var closestAnchor = getClosestAnchorForDrawable(drawable); @@ -286,7 +264,7 @@ namespace osu.Game.Skinning.Editor protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) { int checkAnchor(Drawable drawable) => - isDrawableUsingClosestAnchor(drawable).Value + drawable.IsUsingClosestAnchor().Value ? closest_text_hash : (int)drawable.Anchor; @@ -366,7 +344,7 @@ namespace osu.Game.Skinning.Editor private Anchor getAnchorFromHashAndDrawableAndRecordWhetherUsingClosestAnchor(int hash, Drawable drawable) { - var isUsingClosestAnchor = isDrawableUsingClosestAnchor(drawable); + var isUsingClosestAnchor = drawable.IsUsingClosestAnchor(); if (hash == closest_text_hash) {