1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 06:47:24 +08:00

Replace polling logic with direct bindable reactions

This commit is contained in:
Dean Herbert 2021-05-11 17:49:00 +09:00
parent a88a8b7d8d
commit a4e0529617
4 changed files with 78 additions and 31 deletions

View File

@ -3,9 +3,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
@ -24,6 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// Includes selection and manipulation support via a <see cref="Components.SelectionHandler{T}"/>.
/// </summary>
public abstract class BlueprintContainer<T> : CompositeDrawable, IKeyBindingHandler<PlatformAction>
where T : class
{
protected DragBox DragBox { get; private set; }
@ -39,6 +42,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
[Resolved(CanBeNull = true)]
private IEditorChangeHandler changeHandler { get; set; }
protected readonly BindableList<T> SelectedItems = new BindableList<T>();
protected BlueprintContainer()
{
RelativeSizeAxes = Axes.Both;
@ -47,6 +52,24 @@ namespace osu.Game.Screens.Edit.Compose.Components
[BackgroundDependencyLoader]
private void load()
{
SelectedItems.CollectionChanged += (selectedObjects, args) =>
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var o in args.NewItems)
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Select();
break;
case NotifyCollectionChangedAction.Remove:
foreach (var o in args.OldItems)
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Deselect();
break;
}
};
SelectionHandler = CreateSelectionHandler();
SelectionHandler.DeselectAll = deselectAll;

View File

@ -2,10 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
@ -24,8 +22,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected readonly HitObjectComposer Composer;
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
protected EditorBlueprintContainer(HitObjectComposer composer)
{
Composer = composer;
@ -34,23 +30,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
[BackgroundDependencyLoader]
private void load()
{
selectedHitObjects.BindTo(Beatmap.SelectedHitObjects);
selectedHitObjects.CollectionChanged += (selectedObjects, args) =>
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var o in args.NewItems)
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Select();
break;
case NotifyCollectionChangedAction.Remove:
foreach (var o in args.OldItems)
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Deselect();
break;
}
};
SelectedItems.BindTo(Beatmap.SelectedHitObjects);
}
protected override void LoadComplete()

View File

@ -1,11 +1,16 @@
// 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.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Screens.Play.HUD;
namespace osu.Game.Skinning.Editor
{
@ -18,23 +23,51 @@ namespace osu.Game.Skinning.Editor
this.target = target;
}
[BackgroundDependencyLoader(true)]
private void load(SkinEditor editor)
{
SelectedItems.BindTo(editor.SelectedComponents);
}
private readonly List<BindableList<ISkinnableComponent>> targetComponents = new List<BindableList<ISkinnableComponent>>();
protected override void LoadComplete()
{
base.LoadComplete();
checkForComponents();
// track each target container on the current screen.
foreach (var targetContainer in target.ChildrenOfType<SkinnableElementTargetContainer>())
{
var bindableList = new BindableList<ISkinnableComponent> { BindTarget = targetContainer.Components };
bindableList.BindCollectionChanged(componentsChanged, true);
targetComponents.Add(bindableList);
}
}
private void checkForComponents()
private void componentsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ISkinnableComponent[] skinnableComponents = target.ChildrenOfType<ISkinnableComponent>().ToArray();
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems.Cast<ISkinnableComponent>())
AddBlueprintFor(item);
break;
foreach (var c in skinnableComponents)
AddBlueprintFor(c);
case NotifyCollectionChangedAction.Remove:
case NotifyCollectionChangedAction.Reset:
foreach (var item in e.OldItems.Cast<ISkinnableComponent>())
RemoveBlueprintFor(item);
break;
// We'd hope to eventually be running this in a more sensible way, but this handles situations where new drawables become present (ie. during ongoing gameplay)
// or when drawables in the target are loaded asynchronously and may not be immediately available when this BlueprintContainer is loaded.
Scheduler.AddDelayed(checkForComponents, 1000);
case NotifyCollectionChangedAction.Replace:
foreach (var item in e.OldItems.Cast<ISkinnableComponent>())
RemoveBlueprintFor(item);
foreach (var item in e.NewItems.Cast<ISkinnableComponent>())
AddBlueprintFor(item);
break;
}
}
protected override SelectionHandler<ISkinnableComponent> CreateSelectionHandler() => new SkinSelectionHandler();

View File

@ -18,6 +18,7 @@ using osuTK;
namespace osu.Game.Skinning.Editor
{
[Cached(typeof(SkinEditor))]
public class SkinEditor : FocusedOverlayContainer
{
public const double TRANSITION_DURATION = 500;
@ -28,11 +29,15 @@ namespace osu.Game.Skinning.Editor
protected override bool StartHidden => true;
public readonly BindableList<ISkinnableComponent> SelectedComponents = new BindableList<ISkinnableComponent>();
[Resolved]
private SkinManager skins { get; set; }
private Bindable<Skin> currentSkin;
private SkinBlueprintContainer blueprintContainer;
public SkinEditor(Drawable targetScreen)
{
this.targetScreen = targetScreen;
@ -56,7 +61,7 @@ namespace osu.Game.Skinning.Editor
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X
},
new SkinBlueprintContainer(targetScreen),
blueprintContainer = new SkinBlueprintContainer(targetScreen),
new SkinComponentToolbox(600)
{
Anchor = Anchor.CentreLeft,
@ -109,9 +114,15 @@ namespace osu.Game.Skinning.Editor
private void placeComponent(Type type)
{
Drawable instance = (Drawable)Activator.CreateInstance(type);
var instance = (Drawable)Activator.CreateInstance(type) as ISkinnableComponent;
if (instance == null)
throw new InvalidOperationException("Attempted to instantiate a component for placement which was not an {typeof(ISkinnableComponent)}.");
getTarget(SkinnableTarget.MainHUDComponents)?.Add(instance);
SelectedComponents.Clear();
SelectedComponents.Add(instance);
}
private ISkinnableTarget getTarget(SkinnableTarget target)