diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 5c3d3c03bf..fec1610160 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -9,16 +9,12 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Game.Configuration; -using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD; -using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay @@ -78,29 +74,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("key counter flow not affected", () => keyCounterFlow.IsPresent); } - private IReadOnlyList createSkinSourceComponents() - { - Drawable[] hudComponents = typeof(SkinnableHUDComponent).Assembly - .GetTypes() - .Where(t => typeof(SkinnableHUDComponent).IsAssignableFrom(t)) - .Where(t => !t.IsAbstract) - .Select(t => Activator.CreateInstance(t) as Drawable) - .ToArray(); - - List drawables = new List(); - - foreach (var component in hudComponents) - { - drawables.Add(new OsuSpriteText - { - Text = component.GetType().Name - }); - drawables.AddRange(component.CreateSettingsControls()); - } - - return drawables; - } - private void createNew(Action action = null) { AddStep("create overlay", () => diff --git a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs index d5d8ec570a..b8a43708b4 100644 --- a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class DefaultAccuracyCounter : PercentageCounter, IAccuracyCounter + public class DefaultAccuracyCounter : PercentageCounter, IAccuracyCounter, ISkinnableComponent { private readonly Vector2 offset = new Vector2(-20, 5); diff --git a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs index 63e7a88550..959766ecd1 100644 --- a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class DefaultComboCounter : RollingCounter, IComboCounter + public class DefaultComboCounter : RollingCounter, IComboCounter, ISkinnableComponent { private readonly Vector2 offset = new Vector2(20, 5); diff --git a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs index b550b469e9..e3cd71691d 100644 --- a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs @@ -16,7 +16,7 @@ using osu.Framework.Utils; namespace osu.Game.Screens.Play.HUD { - public class DefaultHealthDisplay : HealthDisplay, IHasAccentColour + public class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISkinnableComponent { /// /// The base opacity of the glow. diff --git a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs index 1dcfe2e067..dde5c18b38 100644 --- a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Play.HUD { - public class DefaultScoreCounter : ScoreCounter + public class DefaultScoreCounter : ScoreCounter, ISkinnableComponent { public DefaultScoreCounter() : base(6) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 89f135de7f..3b24c8cc9e 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { - public class BarHitErrorMeter : HitErrorMeter + public class BarHitErrorMeter : HitErrorMeter, ISkinnableComponent { private readonly Anchor alignment; diff --git a/osu.Game/Screens/Play/HUD/ISkinnableComponent.cs b/osu.Game/Screens/Play/HUD/ISkinnableComponent.cs new file mode 100644 index 0000000000..6d4558443f --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ISkinnableComponent.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; + +namespace osu.Game.Screens.Play.HUD +{ + /// + /// Denotes a drawable which, as a drawable, can be adjusted via skinning specifications. + /// + public interface ISkinnableComponent : IDrawable + { + } +} diff --git a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs index b4604c0d01..4ae722e44c 100644 --- a/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LegacyComboCounter.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Play.HUD /// /// Uses the 'x' symbol and has a pop-out effect while rolling over. /// - public class LegacyComboCounter : CompositeDrawable, IComboCounter + public class LegacyComboCounter : CompositeDrawable, IComboCounter, ISkinnableComponent { public Bindable Current { get; } = new BindableInt { MinValue = 0, }; diff --git a/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs index 33132adf23..76c9c30813 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableAccuracyCounter.cs @@ -2,12 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class SkinnableAccuracyCounter : SkinnableHUDComponent, IAccuracyCounter + public class SkinnableAccuracyCounter : SkinnableDrawable, IAccuracyCounter { public Bindable Current { get; } = new Bindable(); @@ -15,7 +14,6 @@ namespace osu.Game.Screens.Play.HUD : base(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter), _ => new DefaultAccuracyCounter()) { CentreComponent = false; - AutoSizeAxes = Axes.Both; } private IAccuracyCounter skinnedCounter; diff --git a/osu.Game/Screens/Play/HUD/SkinnableComboCounter.cs b/osu.Game/Screens/Play/HUD/SkinnableComboCounter.cs index 8785eccfc3..c04c50141a 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableComboCounter.cs @@ -2,12 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class SkinnableComboCounter : SkinnableHUDComponent, IComboCounter + public class SkinnableComboCounter : SkinnableDrawable, IComboCounter { public Bindable Current { get; } = new Bindable(); @@ -15,7 +14,6 @@ namespace osu.Game.Screens.Play.HUD : base(new HUDSkinComponent(HUDSkinComponents.ComboCounter), skinComponent => new DefaultComboCounter()) { CentreComponent = false; - AutoSizeAxes = Axes.Both; } private IComboCounter skinnedCounter; diff --git a/osu.Game/Screens/Play/HUD/SkinnableHUDComponent.cs b/osu.Game/Screens/Play/HUD/SkinnableHUDComponent.cs deleted file mode 100644 index 7d23611718..0000000000 --- a/osu.Game/Screens/Play/HUD/SkinnableHUDComponent.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Layout; -using osu.Game.Configuration; -using osu.Game.Skinning; -using osuTK; - -namespace osu.Game.Screens.Play.HUD -{ - /// - /// A skinnable HUD component which can be scaled and repositioned at a skinner/user's will. - /// - public abstract class SkinnableHUDComponent : SkinnableDrawable - { - [SettingSource("ScaleX", "The horizontal scale at which this component should be displayed.")] - public BindableNumber SkinScaleX { get; } = new BindableFloat(1); - - [SettingSource("ScaleY", "The vertical scale at which this component should be displayed.")] - public BindableNumber SkinScaleY { get; } = new BindableFloat(1); - - [SettingSource("PositionX", "The horizontal position at which this component should be displayed.")] - public BindableNumber SkinPositionX { get; } = new BindableFloat(); - - [SettingSource("PositionY", "The vertical position at which this component should be displayed.")] - public BindableNumber SkinPositionY { get; } = new BindableFloat(); - - [SettingSource("Rotation", "The rotation at which this component should be displayed.")] - public BindableNumber SkinRotation { get; } = new BindableFloat(); - - [SettingSource("Anchor", "The screen edge this component should align to.")] - public Bindable SkinAnchor { get; } = new Bindable(); - - protected SkinnableHUDComponent(ISkinComponent component, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.NoScaling) - : base(component, defaultImplementation, allowFallback, confineMode) - { - SkinScaleX.BindValueChanged(x => Scale = new Vector2(x.NewValue, Scale.Y)); - SkinScaleY.BindValueChanged(y => Scale = new Vector2(Scale.X, y.NewValue)); - - SkinPositionX.BindValueChanged(x => Position = new Vector2(x.NewValue, Position.Y)); - SkinPositionY.BindValueChanged(y => Position = new Vector2(Position.X, y.NewValue)); - - SkinRotation.BindValueChanged(rotation => Rotation = rotation.NewValue); - SkinAnchor.BindValueChanged(anchor => { Anchor = anchor.NewValue; }); - - // reset everything and require each component to specify what they want, - // as if they were just drawables. maybe we want to change SkinnableDrawable to not default - // to RelativeSizeAxes.Both... - RelativeSizeAxes = Axes.None; - AutoSizeAxes = Axes.None; - } - - protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) - { - SkinScaleX.Value = Scale.X; - SkinScaleY.Value = Scale.Y; - SkinPositionX.Value = Position.X; - SkinPositionY.Value = Position.Y; - SkinRotation.Value = Rotation; - SkinAnchor.Value = Anchor; - - return base.OnInvalidate(invalidation, source); - } - } -} diff --git a/osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs b/osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs index ceac147b63..1f91f5e50f 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs @@ -3,14 +3,13 @@ using System; using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class SkinnableHealthDisplay : SkinnableHUDComponent, IHealthDisplay + public class SkinnableHealthDisplay : SkinnableDrawable, IHealthDisplay { public Bindable Current { get; } = new BindableDouble(1) { @@ -36,8 +35,6 @@ namespace osu.Game.Screens.Play.HUD : base(new HUDSkinComponent(HUDSkinComponents.HealthDisplay), _ => new DefaultHealthDisplay()) { CentreComponent = false; - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; } private IHealthDisplay skinnedCounter; diff --git a/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs b/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs index c47baf95ff..b46f5684b1 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableScoreCounter.cs @@ -4,14 +4,13 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class SkinnableScoreCounter : SkinnableHUDComponent, IScoreCounter + public class SkinnableScoreCounter : SkinnableDrawable, IScoreCounter { public Bindable Current { get; } = new Bindable(); @@ -23,7 +22,6 @@ namespace osu.Game.Screens.Play.HUD : base(new HUDSkinComponent(HUDSkinComponents.ScoreCounter), _ => new DefaultScoreCounter()) { CentreComponent = false; - AutoSizeAxes = Axes.Both; } [BackgroundDependencyLoader] diff --git a/osu.Game/Skinning/Editor/SkinBlueprint.cs b/osu.Game/Skinning/Editor/SkinBlueprint.cs index f9fffab579..674153cb26 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprint.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprint.cs @@ -15,24 +15,25 @@ using osuTK; namespace osu.Game.Skinning.Editor { - public class SkinBlueprint : SelectionBlueprint + public class SkinBlueprint : SelectionBlueprint { /// /// The which this applies to. /// - public readonly SkinnableHUDComponent Component; + public readonly ISkinnableComponent Component; private Container box; - private Drawable drawable => Component.Drawable; + + private Drawable drawable => (Drawable)Component; /// /// Whether the blueprint should be shown even when the is not alive. /// protected virtual bool AlwaysShowWhenSelected => false; - protected override bool ShouldBeAlive => (Component.IsAlive && Component.IsPresent) || (AlwaysShowWhenSelected && State == SelectionState.Selected); + protected override bool ShouldBeAlive => (drawable.IsAlive && Component.IsPresent) || (AlwaysShowWhenSelected && State == SelectionState.Selected); - public SkinBlueprint(SkinnableHUDComponent component) + public SkinBlueprint(ISkinnableComponent component) : base(component) { Component = component; @@ -72,15 +73,15 @@ namespace osu.Game.Skinning.Editor box.Position = quad.TopLeft; box.Size = quad.Size; - box.Rotation = Component.Rotation; + box.Rotation = drawable.Rotation; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => drawable.ReceivePositionalInputAt(screenSpacePos); - public override Vector2 ScreenSpaceSelectionPoint => Component.ToScreenSpace(Vector2.Zero); + public override Vector2 ScreenSpaceSelectionPoint => drawable.ToScreenSpace(Vector2.Zero); public override Quad SelectionQuad => drawable.ScreenSpaceDrawQuad; - public override Vector2 GetInstantDelta(Vector2 screenSpacePosition) => Component.Parent.ToLocalSpace(screenSpacePosition) - Component.Position; + public override Vector2 GetInstantDelta(Vector2 screenSpacePosition) => Component.Parent.ToLocalSpace(screenSpacePosition) - drawable.Position; } } diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs index ddf3fd28a7..f997e84355 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Skinning.Editor { - public class SkinBlueprintContainer : BlueprintContainer + public class SkinBlueprintContainer : BlueprintContainer { private readonly Drawable target; @@ -23,14 +23,14 @@ namespace osu.Game.Skinning.Editor { base.LoadComplete(); - SkinnableHUDComponent[] components = target.ChildrenOfType().ToArray(); + ISkinnableComponent[] components = target.ChildrenOfType().ToArray(); foreach (var c in components) AddBlueprintFor(c); } - protected override SelectionHandler CreateSelectionHandler() => new SkinSelectionHandler(); + protected override SelectionHandler CreateSelectionHandler() => new SkinSelectionHandler(); - protected override SelectionBlueprint CreateBlueprintFor(SkinnableHUDComponent component) + protected override SelectionBlueprint CreateBlueprintFor(ISkinnableComponent component) => new SkinBlueprint(component); } } diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index 55f36c73d6..38404efd0c 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs @@ -14,15 +14,15 @@ using osuTK; namespace osu.Game.Skinning.Editor { - public class SkinSelectionHandler : SelectionHandler + public class SkinSelectionHandler : SelectionHandler { - protected override void DeleteItems(IEnumerable items) + protected override void DeleteItems(IEnumerable items) { foreach (var i in items) - i.Drawable.Expire(); + i.Hide(); } - protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) + protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) { yield return new OsuMenuItem("Anchor") { @@ -49,7 +49,7 @@ namespace osu.Game.Skinning.Editor return displayableAnchors.Select(a => { - var countExisting = selection.Count(b => b.Item.SkinAnchor.Value == a); + var countExisting = selection.Count(b => ((Drawable)b.Item).Anchor == a); var countTotal = selection.Count(); TernaryState state; @@ -72,7 +72,7 @@ namespace osu.Game.Skinning.Editor private void applyAnchor(Anchor anchor) { foreach (var item in SelectedItems) - item.SkinAnchor.Value = anchor; + ((Drawable)item).Anchor = anchor; } protected override void OnSelectionChanged() @@ -88,7 +88,7 @@ namespace osu.Game.Skinning.Editor public override bool HandleRotation(float angle) { foreach (var c in SelectedBlueprints) - c.Item.SkinRotation.Value += angle; + ((Drawable)c.Item).Rotation += angle; return base.HandleRotation(angle); } @@ -98,20 +98,16 @@ namespace osu.Game.Skinning.Editor adjustScaleFromAnchor(ref scale, anchor); foreach (var c in SelectedBlueprints) - { - c.Item.SkinScaleX.Value += scale.X * 0.01f; - c.Item.SkinScaleY.Value += scale.Y * 0.01f; - } + ((Drawable)c.Item).Scale += scale * 0.01f; return true; } - public override bool HandleMovement(MoveSelectionEvent moveEvent) + public override bool HandleMovement(MoveSelectionEvent moveEvent) { foreach (var c in SelectedBlueprints) { - c.Item.SkinPositionX.Value += moveEvent.InstantDelta.X; - c.Item.SkinPositionY.Value += moveEvent.InstantDelta.Y; + ((Drawable)c.Item).Position += moveEvent.InstantDelta; } return true; @@ -130,7 +126,7 @@ namespace osu.Game.Skinning.Editor public class AnchorMenuItem : TernaryStateMenuItem { - public AnchorMenuItem(Anchor anchor, IEnumerable> selection, Action action) + public AnchorMenuItem(Anchor anchor, IEnumerable> selection, Action action) : base(anchor.ToString(), getNextState, MenuItemType.Standard, action) { } diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index 7d6f1dc916..c592e06924 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Skinning { - public class LegacyAccuracyCounter : PercentageCounter, IAccuracyCounter + public class LegacyAccuracyCounter : PercentageCounter, IAccuracyCounter, ISkinnableComponent { private readonly ISkin skin; diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index 2921d46467..2e29abf453 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Skinning { - public class LegacyHealthDisplay : CompositeDrawable, IHealthDisplay + public class LegacyHealthDisplay : CompositeDrawable, IHealthDisplay, ISkinnableComponent { private const double epic_cutoff = 0.5; diff --git a/osu.Game/Skinning/LegacyScoreCounter.cs b/osu.Game/Skinning/LegacyScoreCounter.cs index 1d330ef495..cae8044242 100644 --- a/osu.Game/Skinning/LegacyScoreCounter.cs +++ b/osu.Game/Skinning/LegacyScoreCounter.cs @@ -5,11 +5,12 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Play.HUD; using osuTK; namespace osu.Game.Skinning { - public class LegacyScoreCounter : ScoreCounter + public class LegacyScoreCounter : ScoreCounter, ISkinnableComponent { private readonly ISkin skin;