2019-07-19 09:38:24 +00:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 08:43:03 +00:00
// See the LICENCE file in the repository root for full licence text.
2018-04-13 09:19:50 +00:00
using System ;
2019-07-18 08:52:50 +00:00
using osu.Framework.Caching ;
2018-04-13 09:19:50 +00:00
using osu.Framework.Graphics ;
2018-11-20 07:51:59 +00:00
using osuTK ;
2018-04-13 09:19:50 +00:00
namespace osu.Game.Skinning
{
2019-06-24 06:25:01 +00:00
/// <summary>
/// A drawable which can be skinned via an <see cref="ISkinSource"/>.
/// </summary>
2019-07-19 09:38:24 +00:00
public class SkinnableDrawable : SkinReloadableDrawable
2018-04-13 09:19:50 +00:00
{
2018-09-27 08:33:27 +00:00
/// <summary>
2019-07-19 09:38:24 +00:00
/// The displayed component.
2018-09-27 08:33:27 +00:00
/// </summary>
2019-08-28 10:57:17 +00:00
public Drawable Drawable { get ; private set ; }
2018-09-27 07:27:11 +00:00
2020-03-31 06:28:50 +00:00
public new Axes AutoSizeAxes
{
get = > base . AutoSizeAxes ;
set = > base . AutoSizeAxes = value ;
}
2019-08-30 05:39:02 +00:00
private readonly ISkinComponent component ;
2018-04-13 09:19:50 +00:00
2019-07-18 03:10:28 +00:00
private readonly ConfineMode confineMode ;
2018-04-13 09:19:50 +00:00
/// <summary>
2019-06-24 06:25:01 +00:00
/// Create a new skinnable drawable.
2018-04-13 09:19:50 +00:00
/// </summary>
2019-08-30 05:39:02 +00:00
/// <param name="component">The namespace-complete resource name for this skinnable element.</param>
2018-04-13 09:19:50 +00:00
/// <param name="defaultImplementation">A function to create the default skin implementation of this element.</param>
/// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
2019-07-18 03:10:28 +00:00
/// <param name="confineMode">How (if at all) the <see cref="Drawable"/> should be resize to fit within our own bounds.</param>
2019-12-06 05:40:45 +00:00
public SkinnableDrawable ( ISkinComponent component , Func < ISkinComponent , Drawable > defaultImplementation , Func < ISkinSource , bool > allowFallback = null , ConfineMode confineMode = ConfineMode . NoScaling )
2019-08-30 05:39:02 +00:00
: this ( component , allowFallback , confineMode )
2019-06-24 05:39:20 +00:00
{
createDefault = defaultImplementation ;
}
2019-12-06 05:40:45 +00:00
protected SkinnableDrawable ( ISkinComponent component , Func < ISkinSource , bool > allowFallback = null , ConfineMode confineMode = ConfineMode . NoScaling )
2018-09-27 07:27:11 +00:00
: base ( allowFallback )
2018-04-13 09:19:50 +00:00
{
2019-08-30 05:39:02 +00:00
this . component = component ;
2019-07-18 03:10:28 +00:00
this . confineMode = confineMode ;
2018-04-13 09:19:50 +00:00
RelativeSizeAxes = Axes . Both ;
}
2019-08-30 05:39:02 +00:00
private readonly Func < ISkinComponent , Drawable > createDefault ;
2019-06-24 06:27:46 +00:00
2019-07-18 08:52:50 +00:00
private readonly Cached scaling = new Cached ( ) ;
private bool isDefault ;
2019-08-30 05:39:02 +00:00
protected virtual Drawable CreateDefault ( ISkinComponent component ) = > createDefault ( component ) ;
2019-06-24 06:27:46 +00:00
2019-06-24 06:25:01 +00:00
/// <summary>
2019-07-18 03:10:28 +00:00
/// Whether to apply size restrictions (specified via <see cref="confineMode"/>) to the default implementation.
2019-06-24 06:25:01 +00:00
/// </summary>
protected virtual bool ApplySizeRestrictionsToDefault = > false ;
2019-06-24 05:39:20 +00:00
2018-04-13 09:19:50 +00:00
protected override void SkinChanged ( ISkinSource skin , bool allowFallback )
{
2019-08-30 05:39:02 +00:00
Drawable = skin . GetDrawableComponent ( component ) ;
2018-09-27 07:27:11 +00:00
2019-07-18 08:52:50 +00:00
isDefault = false ;
2019-06-24 05:39:20 +00:00
if ( Drawable = = null & & allowFallback )
{
2019-08-30 05:39:02 +00:00
Drawable = CreateDefault ( component ) ;
2019-06-24 05:39:20 +00:00
isDefault = true ;
}
2018-09-27 07:27:11 +00:00
if ( Drawable ! = null )
2018-04-13 09:19:50 +00:00
{
2019-07-18 08:52:50 +00:00
scaling . Invalidate ( ) ;
Drawable . Origin = Anchor . Centre ;
Drawable . Anchor = Anchor . Centre ;
InternalChild = Drawable ;
}
else
ClearInternal ( ) ;
}
protected override void Update ( )
{
base . Update ( ) ;
if ( ! scaling . IsValid )
{
2019-07-18 09:39:33 +00:00
try
2018-04-13 09:19:50 +00:00
{
2019-07-18 09:39:33 +00:00
if ( Drawable = = null | | ( isDefault & & ! ApplySizeRestrictionsToDefault ) ) return ;
2019-07-18 03:10:28 +00:00
2019-07-18 09:39:33 +00:00
switch ( confineMode )
2019-07-18 03:10:28 +00:00
{
2020-03-31 14:35:23 +00:00
case ConfineMode . ScaleToFit :
Drawable . RelativeSizeAxes = Axes . Both ;
Drawable . Size = Vector2 . One ;
Drawable . Scale = Vector2 . One ;
Drawable . FillMode = FillMode . Fit ;
2019-07-18 09:39:33 +00:00
break ;
2019-07-18 03:10:28 +00:00
}
2019-07-18 09:39:33 +00:00
}
finally
{
scaling . Validate ( ) ;
}
2018-04-13 09:19:50 +00:00
}
}
}
2019-07-18 03:10:28 +00:00
public enum ConfineMode
{
/// <summary>
/// Don't apply any scaling. This allows the user element to be of any size, exceeding specified bounds.
/// </summary>
NoScaling ,
ScaleToFit ,
}
2018-04-13 09:19:50 +00:00
}