1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 12:17:26 +08:00

Move lookup logic to DrawableExtensions

This is now a global lookup to be shared by serialization and editor.
This commit is contained in:
Robin Avery 2021-06-06 06:58:21 -04:00
parent 4aee76456f
commit c9f5808bf2
No known key found for this signature in database
GPG Key ID: 0496DF10CEF7E226
2 changed files with 28 additions and 25 deletions

View File

@ -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());
}
}
/// <remarks>
/// <p>A <see cref="ConditionalWeakTable{TKey,TValue}">ConditionalWeakTable</see> is preferable to a <see cref="Dictionary{TKey,TValue}">Dictionary</see> because a <c>Dictionary</c> will keep
/// orphaned references to an <see cref="ISkinnableDrawable"/> forever, unless manually pruned.</p>
/// <p><see cref="BindableBool"/> is used as a thin wrapper around <see cref="System.Boolean">bool</see> because <c>ConditionalWeakTable</c> requires a reference type as both a key and a value.</p>
/// <p><see cref="IDrawable"/> was chosen over <see cref="Drawable"/> because it is a common ancestor between <see cref="Drawable"/> (which is required for <see cref="Drawable.Anchor"/> logic)
/// and <see cref="ISkinnableDrawable"/> (which is required for serialization via <see cref="SkinnableInfo"/>).</p>
/// <p>This collection is thread-safe according to the
/// <a href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.conditionalweaktable-2?view=net-5.0#thread-safety">documentation</a>,
/// but the <c>BindableBool</c>s are not unless <see cref="Bindable{T}.BeginLease">leased</see>.</p>
/// </remarks>
private static readonly ConditionalWeakTable<IDrawable, BindableBool> is_drawable_using_closest_anchor_lookup = new ConditionalWeakTable<IDrawable, BindableBool>();
/// <summary>
/// Gets or creates a <see cref="BindableBool"/> representing whether <paramref name="drawable"/> is using the closest <see cref="Drawable.Anchor">anchor point</see> within its
/// <see cref="Drawable.Parent">parent</see>.
/// </summary>
/// <returns>A <see cref="BindableBool"/> whose <see cref="Bindable{T}.Value"/> is <see langword="true"/> if the <see cref="IDrawable"/> is using the closest anchor point,
/// otherwise <see langword="false"/>.</returns>
public static BindableBool IsUsingClosestAnchor(this IDrawable drawable) =>
is_drawable_using_closest_anchor_lookup.GetValue(drawable, _ => new BindableBool(true));
}
}

View File

@ -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<ISkinnableDrawable>
{
/// <summary>
/// <p>Keeps track of whether a <see cref="Drawable"/> is using the closest <see cref="Drawable.Anchor">anchor point</see> within its <see cref="Drawable.Parent">parent</see>,
/// or whether the user is overriding its anchor point.</p>
/// <p>Each <see cref="KeyValuePair{TKey,TValue}.Key">key</see> is either a direct cast of an Anchor value, or it is equal to <see cref="closest_text_hash"/>. This is done
/// because the "Closest" menu item is not a valid anchor, so something other than an anchor must be used.</p>
/// <p>Each <see cref="KeyValuePair{TKey,TValue}.Value">value</see> is a <see cref="BindableBool"/>. If the <see cref="Bindable{T}.Value"/> is <see langword="false"/>, the user has
/// overridden the anchor point.
/// If <see langword="true"/>, the closest anchor point is assigned to the Drawable when it is either dragged by the user via <see cref="HandleMovement"/>, or when "Closest" is assigned from
/// the anchor context menu via <see cref="applyAnchor"/>.</p>
/// </summary>
/// <remarks>
/// <p>A <see cref="ConditionalWeakTable{TKey,TValue}">ConditionalWeakTable</see> is preferable to a <see cref="Dictionary{TKey,TValue}">Dictionary</see> because a Dictionary will keep
/// orphaned references to a Drawable forever, unless manually pruned</p>
/// <p><see cref="BindableBool"/> is used as a thin wrapper around <see cref="Boolean">bool</see> because ConditionalWeakTable requires a reference type as both a key and a value.</p>
/// </remarks>
private readonly ConditionalWeakTable<Drawable, BindableBool> isDrawableUsingClosestAnchorLookup = new ConditionalWeakTable<Drawable, BindableBool>();
private const string closest_text = @"Closest";
/// <summary>
@ -118,9 +99,6 @@ namespace osu.Game.Skinning.Editor
return result;
}
/// <remarks>Defaults to <see langword="true"/>, meaning anchors are closest by default.</remarks>
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<MenuItem> GetContextMenuItemsForSelection(IEnumerable<SelectionBlueprint<ISkinnableDrawable>> 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)
{