2020-01-27 07:00:51 +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
2022-06-17 07:37:17 +00:00
#nullable disable
2018-03-20 11:09:55 +00:00
using System.Linq ;
2019-02-21 10:04:31 +00:00
using osu.Framework.Bindables ;
2019-08-30 08:34:02 +00:00
using osu.Game.Graphics ;
2022-02-13 14:50:40 +00:00
using osu.Game.Screens.Edit.Compose.Components ;
2022-05-24 08:02:19 +00:00
using osuTK ;
2019-08-30 08:34:02 +00:00
using osuTK.Graphics ;
2018-04-13 09:19:50 +00:00
2018-11-06 09:28:22 +00:00
namespace osu.Game.Screens.Edit
2018-03-19 11:30:07 +00:00
{
2019-10-23 05:04:06 +00:00
public class BindableBeatDivisor : BindableInt
2018-03-19 11:30:07 +00:00
{
2022-02-13 14:50:40 +00:00
public static readonly int [ ] PREDEFINED_DIVISORS = { 1 , 2 , 3 , 4 , 6 , 8 , 12 , 16 } ;
2024-08-20 11:36:52 +00:00
public const int MINIMUM_DIVISOR = 1 ;
public const int MAXIMUM_DIVISOR = 64 ;
2022-02-13 14:50:40 +00:00
public Bindable < BeatDivisorPresetCollection > ValidDivisors { get ; } = new Bindable < BeatDivisorPresetCollection > ( BeatDivisorPresetCollection . COMMON ) ;
2018-04-13 09:19:50 +00:00
2018-03-19 11:42:06 +00:00
public BindableBeatDivisor ( int value = 1 )
: base ( value )
2018-03-19 11:30:07 +00:00
{
2022-02-13 14:50:40 +00:00
ValidDivisors . BindValueChanged ( _ = > updateBindableProperties ( ) , true ) ;
BindValueChanged ( _ = > ensureValidDivisor ( ) ) ;
2018-03-19 11:30:07 +00:00
}
2018-04-13 09:19:50 +00:00
2022-10-24 06:20:15 +00:00
/// <summary>
/// Set a divisor, updating the valid divisor range appropriately.
/// </summary>
/// <param name="divisor">The intended divisor.</param>
2024-01-25 10:12:54 +00:00
/// <param name="preferKnownPresets">Forces changing the valid divisors to a known preset.</param>
2024-08-20 11:36:52 +00:00
/// <returns>Whether the divisor was successfully set.</returns>
public bool SetArbitraryDivisor ( int divisor , bool preferKnownPresets = false )
2022-10-24 06:20:15 +00:00
{
2024-08-20 11:36:52 +00:00
if ( divisor < MINIMUM_DIVISOR | | divisor > MAXIMUM_DIVISOR )
return false ;
2022-10-24 06:20:15 +00:00
// If the current valid divisor range doesn't contain the proposed value, attempt to find one which does.
2024-01-25 10:12:54 +00:00
if ( preferKnownPresets | | ! ValidDivisors . Value . Presets . Contains ( divisor ) )
2022-10-24 06:20:15 +00:00
{
if ( BeatDivisorPresetCollection . COMMON . Presets . Contains ( divisor ) )
ValidDivisors . Value = BeatDivisorPresetCollection . COMMON ;
else if ( BeatDivisorPresetCollection . TRIPLETS . Presets . Contains ( divisor ) )
ValidDivisors . Value = BeatDivisorPresetCollection . TRIPLETS ;
else
ValidDivisors . Value = BeatDivisorPresetCollection . Custom ( divisor ) ;
}
Value = divisor ;
2024-08-20 11:36:52 +00:00
return true ;
2022-10-24 06:20:15 +00:00
}
2022-02-13 14:50:40 +00:00
private void updateBindableProperties ( )
{
ensureValidDivisor ( ) ;
2018-04-13 09:19:50 +00:00
2022-02-13 14:50:40 +00:00
MinValue = ValidDivisors . Value . Presets . Min ( ) ;
MaxValue = ValidDivisors . Value . Presets . Max ( ) ;
}
2018-04-13 09:19:50 +00:00
2022-02-13 14:50:40 +00:00
private void ensureValidDivisor ( )
2018-03-20 11:09:55 +00:00
{
2022-02-13 14:50:40 +00:00
if ( ! ValidDivisors . Value . Presets . Contains ( Value ) )
Value = 1 ;
}
2018-04-13 09:19:50 +00:00
2023-06-07 15:53:58 +00:00
public void SelectNext ( )
2022-02-13 14:50:40 +00:00
{
var presets = ValidDivisors . Value . Presets ;
2023-06-07 15:53:58 +00:00
if ( presets . Cast < int? > ( ) . SkipWhile ( preset = > preset ! = Value ) . ElementAtOrDefault ( 1 ) is int newValue )
Value = newValue ;
2022-02-13 14:50:40 +00:00
}
2023-06-07 15:53:58 +00:00
public void SelectPrevious ( )
2022-02-13 14:50:40 +00:00
{
var presets = ValidDivisors . Value . Presets ;
2023-06-07 15:53:58 +00:00
if ( presets . Cast < int? > ( ) . TakeWhile ( preset = > preset ! = Value ) . LastOrDefault ( ) is int newValue )
Value = newValue ;
2018-03-20 11:09:55 +00:00
}
2018-04-13 09:19:50 +00:00
2018-03-20 11:09:55 +00:00
protected override int DefaultPrecision = > 1 ;
2019-08-30 08:34:02 +00:00
2022-02-13 14:50:40 +00:00
public override void BindTo ( Bindable < int > them )
{
2022-02-13 15:27:12 +00:00
// bind to valid divisors first (if applicable) to ensure correct transfer of the actual divisor.
2022-02-13 14:50:40 +00:00
if ( them is BindableBeatDivisor otherBeatDivisor )
ValidDivisors . BindTo ( otherBeatDivisor . ValidDivisors ) ;
2022-02-13 15:27:12 +00:00
base . BindTo ( them ) ;
2022-02-13 14:50:40 +00:00
}
2021-08-18 01:16:57 +00:00
protected override Bindable < int > CreateInstance ( ) = > new BindableBeatDivisor ( ) ;
2019-08-30 08:34:02 +00:00
/// <summary>
/// Retrieves the appropriate colour for a beat divisor.
/// </summary>
/// <param name="beatDivisor">The beat divisor.</param>
/// <param name="colours">The set of colours.</param>
/// <returns>The applicable colour from <paramref name="colours"/> for <paramref name="beatDivisor"/>.</returns>
2021-03-19 10:45:00 +00:00
public static Color4 GetColourFor ( int beatDivisor , OsuColour colours )
2019-08-30 08:34:02 +00:00
{
switch ( beatDivisor )
{
2020-01-27 06:57:55 +00:00
case 1 :
return Color4 . White ;
2019-08-30 08:34:02 +00:00
case 2 :
2020-01-27 06:57:55 +00:00
return colours . Red ;
2019-08-30 08:34:02 +00:00
case 4 :
return colours . Blue ;
case 8 :
2020-01-27 06:57:55 +00:00
return colours . Yellow ;
2019-08-30 08:34:02 +00:00
case 16 :
return colours . PurpleDark ;
case 3 :
2020-01-27 06:57:55 +00:00
return colours . Purple ;
2019-08-30 08:34:02 +00:00
case 6 :
2020-01-27 06:57:55 +00:00
return colours . YellowDark ;
2019-08-30 08:34:02 +00:00
case 12 :
return colours . YellowDarker ;
default :
2020-01-27 06:57:55 +00:00
return Color4 . Red ;
2019-08-30 08:34:02 +00:00
}
}
2020-01-27 07:00:51 +00:00
2022-05-24 08:02:19 +00:00
/// <summary>
/// Get a relative display size for the specified divisor.
/// </summary>
/// <param name="beatDivisor">The beat divisor.</param>
/// <returns>A relative size which can be used to display ticks.</returns>
public static Vector2 GetSize ( int beatDivisor )
{
switch ( beatDivisor )
{
case 1 :
case 2 :
2024-08-20 13:24:48 +00:00
return new Vector2 ( 1 , 0.9f ) ;
2022-05-24 08:02:19 +00:00
case 3 :
case 4 :
2024-08-20 13:24:48 +00:00
return new Vector2 ( 0.8f , 0.8f ) ;
2022-05-24 08:02:19 +00:00
case 6 :
case 8 :
2024-08-20 13:24:48 +00:00
return new Vector2 ( 0.8f , 0.7f ) ;
2022-05-24 08:02:19 +00:00
default :
2024-08-20 13:24:48 +00:00
return new Vector2 ( 0.8f , 0.6f ) ;
2022-05-24 08:02:19 +00:00
}
}
2020-01-27 07:00:51 +00:00
/// <summary>
/// Retrieves the applicable divisor for a specific beat index.
/// </summary>
/// <param name="index">The 0-based beat index.</param>
/// <param name="beatDivisor">The beat divisor.</param>
2023-05-24 20:17:51 +00:00
/// <param name="validDivisors">The list of valid divisors which can be chosen from. Assumes ordered from low to high. Defaults to <see cref="PREDEFINED_DIVISORS"/> if omitted.</param>
2020-01-27 07:00:51 +00:00
/// <returns>The applicable divisor.</returns>
2023-05-23 13:05:38 +00:00
public static int GetDivisorForBeatIndex ( int index , int beatDivisor , int [ ] validDivisors = null )
2020-01-27 07:00:51 +00:00
{
2023-05-23 13:05:38 +00:00
validDivisors ? ? = PREDEFINED_DIVISORS ;
2020-01-27 07:00:51 +00:00
int beat = index % beatDivisor ;
2023-05-23 13:05:38 +00:00
foreach ( int divisor in validDivisors )
2020-01-27 07:00:51 +00:00
{
if ( ( beat * divisor ) % beatDivisor = = 0 )
return divisor ;
}
return 0 ;
}
2018-03-19 11:30:07 +00:00
}
}