2021-07-08 06:53:49 +00:00
// 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.
2022-06-17 07:37:17 +00:00
#nullable disable
2021-08-25 04:40:41 +00:00
using System ;
2021-07-08 06:53:49 +00:00
using osu.Framework.Allocation ;
using osu.Framework.Bindables ;
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
using osu.Framework.Graphics.UserInterface ;
using osu.Game.Beatmaps ;
2022-06-28 14:33:05 +00:00
using osu.Game.Graphics.UserInterface ;
2021-07-08 06:53:49 +00:00
using osu.Game.Overlays.Settings ;
namespace osu.Game.Rulesets.Mods
{
public partial class DifficultyAdjustSettingsControl : SettingsItem < float? >
{
[Resolved]
private IBindable < WorkingBeatmap > beatmap { get ; set ; }
2021-07-08 08:39:59 +00:00
/// <summary>
/// Used to track the display value on the setting slider.
/// </summary>
2021-07-09 04:50:07 +00:00
/// <remarks>
/// When the mod is overriding a default, this will match the value of <see cref="Current"/>.
2021-07-09 04:58:44 +00:00
/// When there is no override (ie. <see cref="Current"/> is null), this value will match the beatmap provided default via <see cref="updateCurrentFromSlider"/>.
2021-07-09 04:50:07 +00:00
/// </remarks>
2023-09-07 06:11:04 +00:00
private readonly BindableNumber < float > sliderDisplayCurrent = new BindableNumber < float > ( ) ;
2021-07-08 06:53:49 +00:00
2023-09-07 06:11:04 +00:00
protected sealed override Drawable CreateControl ( ) = > new SliderControl ( sliderDisplayCurrent , CreateSlider ) ;
protected virtual RoundedSliderBar < float > CreateSlider ( BindableNumber < float > current ) = > new RoundedSliderBar < float >
{
RelativeSizeAxes = Axes . X ,
Current = current ,
KeyboardStep = 0.1f ,
} ;
2021-07-08 06:53:49 +00:00
2021-07-09 04:58:44 +00:00
/// <summary>
/// Guards against beatmap values displayed on slider bars being transferred to user override.
/// </summary>
2021-07-08 06:53:49 +00:00
private bool isInternalChange ;
2021-07-08 07:40:32 +00:00
private DifficultyBindable difficultyBindable ;
public override Bindable < float? > Current
{
get = > base . Current ;
set
{
2021-07-09 04:50:07 +00:00
// Intercept and extract the internal number bindable from DifficultyBindable.
// This will provide bounds and precision specifications for the slider bar.
2021-08-18 01:16:57 +00:00
difficultyBindable = ( DifficultyBindable ) value . GetBoundCopy ( ) ;
2023-09-07 06:11:04 +00:00
sliderDisplayCurrent . BindTo ( difficultyBindable . CurrentNumber ) ;
2021-07-08 08:39:59 +00:00
2021-07-11 13:12:46 +00:00
base . Current = difficultyBindable ;
2021-07-08 07:40:32 +00:00
}
}
2021-07-08 06:53:49 +00:00
protected override void LoadComplete ( )
{
base . LoadComplete ( ) ;
2022-06-24 12:25:23 +00:00
Current . BindValueChanged ( _ = > updateCurrentFromSlider ( ) ) ;
beatmap . BindValueChanged ( _ = > updateCurrentFromSlider ( ) , true ) ;
2021-07-08 06:53:49 +00:00
2023-09-07 06:11:04 +00:00
sliderDisplayCurrent . BindValueChanged ( number = >
2021-07-08 06:53:49 +00:00
{
2021-07-09 04:50:07 +00:00
// this handles the transfer of the slider value to the main bindable.
// as such, should be skipped if the slider is being updated via updateFromDifficulty().
2021-07-08 06:53:49 +00:00
if ( ! isInternalChange )
Current . Value = number . NewValue ;
} ) ;
}
2021-07-09 04:58:44 +00:00
private void updateCurrentFromSlider ( )
2021-07-08 06:53:49 +00:00
{
2021-07-09 04:58:44 +00:00
if ( Current . Value ! = null )
{
// a user override has been added or updated.
2023-09-07 06:11:04 +00:00
sliderDisplayCurrent . Value = Current . Value . Value ;
2021-07-09 04:58:44 +00:00
return ;
}
2022-01-18 13:57:39 +00:00
var difficulty = beatmap . Value . BeatmapInfo . Difficulty ;
2021-07-08 06:53:49 +00:00
2021-07-09 04:58:44 +00:00
// generally should always be implemented, else the slider will have a zero default.
if ( difficultyBindable . ReadCurrentFromDifficulty = = null )
return ;
isInternalChange = true ;
2023-09-07 06:11:04 +00:00
sliderDisplayCurrent . Value = difficultyBindable . ReadCurrentFromDifficulty ( difficulty ) ;
2021-07-09 04:58:44 +00:00
isInternalChange = false ;
2021-07-08 06:53:49 +00:00
}
2023-09-07 06:11:04 +00:00
private partial class SliderControl : CompositeDrawable , IHasCurrentValue < float? >
2021-07-08 06:53:49 +00:00
{
2021-07-09 04:50:07 +00:00
// This is required as SettingsItem relies heavily on this bindable for internal use.
// The actual update flow is done via the bindable provided in the constructor.
2021-08-25 04:40:41 +00:00
private readonly DifficultyBindableWithCurrent current = new DifficultyBindableWithCurrent ( ) ;
2021-08-16 09:47:56 +00:00
public Bindable < float? > Current
{
get = > current . Current ;
set = > current . Current = value ;
}
2021-07-08 06:53:49 +00:00
2023-09-07 06:11:04 +00:00
public SliderControl ( BindableNumber < float > currentNumber , Func < BindableNumber < float > , RoundedSliderBar < float > > createSlider )
2021-07-08 06:53:49 +00:00
{
InternalChildren = new Drawable [ ]
{
2023-09-07 06:11:04 +00:00
createSlider ( currentNumber )
2021-07-08 06:53:49 +00:00
} ;
AutoSizeAxes = Axes . Y ;
RelativeSizeAxes = Axes . X ;
}
}
2021-08-25 04:40:41 +00:00
private class DifficultyBindableWithCurrent : DifficultyBindable , IHasCurrentValue < float? >
{
private Bindable < float? > currentBound ;
public Bindable < float? > Current
{
get = > this ;
set
{
2022-12-22 20:27:59 +00:00
ArgumentNullException . ThrowIfNull ( value ) ;
2021-08-25 04:40:41 +00:00
if ( currentBound ! = null ) UnbindFrom ( currentBound ) ;
BindTo ( currentBound = value ) ;
}
}
public DifficultyBindableWithCurrent ( float? defaultValue = default )
: base ( defaultValue )
{
}
protected override Bindable < float? > CreateInstance ( ) = > new DifficultyBindableWithCurrent ( ) ;
}
2021-07-08 06:53:49 +00:00
}
}