2019-01-24 16:43:03 +08: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.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2019-03-06 19:30:14 +08:00
using System ;
2019-04-08 17:32:05 +08:00
using System.Collections.Generic ;
2023-02-16 18:20:06 +08:00
using JetBrains.Annotations ;
2017-03-11 13:27:18 +08:00
using osu.Framework.Allocation ;
2019-02-21 18:04:31 +08:00
using osu.Framework.Bindables ;
2021-05-11 11:42:32 +08:00
using osu.Framework.Extensions.EnumExtensions ;
2017-03-11 13:27:18 +08:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
2023-07-28 14:48:21 +08:00
using osu.Framework.Graphics.Primitives ;
2020-10-30 13:19:40 +08:00
using osu.Framework.Input.Bindings ;
2021-09-16 17:26:12 +08:00
using osu.Framework.Input.Events ;
2017-03-11 13:27:18 +08:00
using osu.Game.Configuration ;
2020-10-30 13:19:40 +08:00
using osu.Game.Input.Bindings ;
2023-06-15 03:13:35 +08:00
using osu.Game.Localisation ;
2017-04-02 21:18:01 +08:00
using osu.Game.Overlays ;
using osu.Game.Overlays.Notifications ;
2023-06-15 03:13:35 +08:00
using osu.Game.Rulesets ;
2019-04-08 17:32:05 +08:00
using osu.Game.Rulesets.Mods ;
2022-02-03 13:50:40 +08:00
using osu.Game.Rulesets.Scoring ;
2017-05-05 12:00:05 +08:00
using osu.Game.Rulesets.UI ;
using osu.Game.Screens.Play.HUD ;
2022-08-15 02:12:11 +08:00
using osu.Game.Screens.Play.HUD.ClicksPerSecond ;
2023-01-17 16:55:45 +08:00
using osu.Game.Screens.Play.HUD.JudgementCounter ;
2021-04-30 11:42:32 +08:00
using osu.Game.Skinning ;
2018-11-20 15:51:59 +08:00
using osuTK ;
2018-04-13 17:19:50 +08:00
2017-05-05 12:00:05 +08:00
namespace osu.Game.Screens.Play
2017-03-11 13:27:18 +08:00
{
2020-10-14 16:21:56 +08:00
[Cached]
2021-05-10 21:43:48 +08:00
public partial class HUDOverlay : Container , IKeyBindingHandler < GlobalAction >
2017-03-11 13:27:18 +08:00
{
2021-04-14 13:25:16 +08:00
public const float FADE_DURATION = 300 ;
2020-10-15 15:56:05 +08:00
2021-04-14 13:25:16 +08:00
public const Easing FADE_EASING = Easing . OutQuint ;
2018-04-13 17:19:50 +08:00
2021-05-17 17:26:30 +08:00
/// <summary>
/// The total height of all the bottom of screen scoring elements.
/// </summary>
public float BottomScoringElementsHeight { get ; private set ; }
2022-10-30 20:38:45 +08:00
protected override bool ShouldBeConsideredForInput ( Drawable child )
{
// HUD uses AlwaysVisible on child components so they can be in an updated state for next display.
// Without blocking input, this would also allow them to be interacted with in such a state.
if ( ShowHud . Value )
return base . ShouldBeConsideredForInput ( child ) ;
// hold to quit button should always be interactive.
return child = = bottomRightElements ;
}
2022-10-10 14:57:41 +08:00
2017-05-05 12:00:05 +08:00
public readonly ModDisplay ModDisplay ;
2018-11-07 00:47:02 +08:00
public readonly HoldForMenuButton HoldToQuit ;
2018-01-14 03:25:09 +08:00
public readonly PlayerSettingsOverlay PlayerSettingsOverlay ;
2018-04-13 17:19:50 +08:00
2022-08-15 00:53:00 +08:00
[Cached]
2023-06-27 15:38:46 +08:00
private readonly ClicksPerSecondController clicksPerSecondController ;
2022-08-09 03:27:46 +08:00
2023-06-15 03:13:35 +08:00
[Cached]
2023-06-27 01:27:42 +08:00
public readonly InputCountController InputCountController ;
2023-06-15 03:13:35 +08:00
2022-12-12 05:08:48 +08:00
[Cached]
2023-06-27 01:30:04 +08:00
private readonly JudgementCountController judgementCountController ;
2022-12-12 05:08:48 +08:00
2021-12-10 13:15:00 +08:00
public Bindable < bool > ShowHealthBar = new Bindable < bool > ( true ) ;
2019-07-07 04:30:53 +08:00
2023-07-29 07:07:08 +08:00
[CanBeNull]
2019-05-09 17:06:11 +08:00
private readonly DrawableRuleset drawableRuleset ;
2023-07-29 07:07:08 +08:00
2019-05-09 17:06:11 +08:00
private readonly IReadOnlyList < Mod > mods ;
2019-12-12 14:05:29 +08:00
/// <summary>
/// Whether the elements that can optionally be hidden should be visible.
/// </summary>
public Bindable < bool > ShowHud { get ; } = new BindableBool ( ) ;
2020-07-22 11:41:06 +08:00
private Bindable < HUDVisibilityMode > configVisibilityMode ;
2023-07-29 02:39:41 +08:00
private Bindable < bool > configLeaderboardVisibility ;
2023-07-05 23:46:28 +08:00
private Bindable < bool > configSettingsOverlay ;
2019-12-12 14:05:29 +08:00
2018-01-17 16:37:14 +08:00
private readonly BindableBool replayLoaded = new BindableBool ( ) ;
2018-04-13 17:19:50 +08:00
2017-04-03 19:58:38 +08:00
private static bool hasShownNotificationOnce ;
2018-04-13 17:19:50 +08:00
2020-10-14 18:16:25 +08:00
private readonly FillFlowContainer bottomRightElements ;
2020-10-15 16:11:02 +08:00
private readonly FillFlowContainer topRightElements ;
2019-07-07 04:30:53 +08:00
2022-04-26 10:19:19 +08:00
internal readonly IBindable < bool > IsPlaying = new Bindable < bool > ( ) ;
2020-07-22 11:41:06 +08:00
2022-05-11 15:09:16 +08:00
public IBindable < bool > HoldingForHUD = > holdingForHUD ;
private readonly BindableBool holdingForHUD = new BindableBool ( ) ;
2020-10-30 13:19:40 +08:00
2023-02-15 17:31:55 +08:00
private readonly SkinComponentsContainer mainComponents ;
2021-05-11 11:42:32 +08:00
2024-01-18 14:44:27 +08:00
[CanBeNull]
private readonly SkinComponentsContainer rulesetComponents ;
2022-09-13 17:23:47 +08:00
/// <summary>
/// A flow which sits at the left side of the screen to house leaderboard (and related) components.
/// Will automatically be positioned to avoid colliding with top scoring elements.
/// </summary>
public readonly FillFlowContainer LeaderboardFlow ;
2022-09-13 17:12:49 +08:00
private readonly List < Drawable > hideTargets ;
2019-12-12 14:05:29 +08:00
2024-05-27 13:38:43 +08:00
/// <summary>
2024-05-27 14:26:00 +08:00
/// The container for skin components attached to <see cref="SkinComponentsContainerLookup.TargetArea.Playfield"/>
2024-05-27 13:38:43 +08:00
/// </summary>
internal readonly Drawable PlayfieldSkinLayer ;
2023-07-28 14:48:21 +08:00
2023-07-29 07:07:08 +08:00
public HUDOverlay ( [ CanBeNull ] DrawableRuleset drawableRuleset , IReadOnlyList < Mod > mods , bool alwaysShowLeaderboard = true )
2017-03-11 13:27:18 +08:00
{
2019-05-09 17:06:11 +08:00
this . drawableRuleset = drawableRuleset ;
this . mods = mods ;
2017-03-11 13:27:18 +08:00
RelativeSizeAxes = Axes . Both ;
2018-04-13 17:19:50 +08:00
2023-02-17 17:40:32 +08:00
Children = new [ ]
2017-03-11 13:27:18 +08:00
{
2021-05-07 16:27:34 +08:00
CreateFailingLayer ( ) ,
2022-12-15 06:00:34 +08:00
//Needs to be initialized before skinnable drawables.
2023-06-27 01:30:04 +08:00
judgementCountController = new JudgementCountController ( ) ,
2023-06-27 15:38:46 +08:00
clicksPerSecondController = new ClicksPerSecondController ( ) ,
2023-06-27 15:37:22 +08:00
InputCountController = new InputCountController ( ) ,
2023-02-16 18:20:06 +08:00
mainComponents = new HUDComponentsContainer { AlwaysPresent = true , } ,
2024-01-18 14:44:27 +08:00
drawableRuleset ! = null
? ( rulesetComponents = new HUDComponentsContainer ( drawableRuleset . Ruleset . RulesetInfo ) { AlwaysPresent = true , } )
2023-02-17 17:40:32 +08:00
: Empty ( ) ,
2024-05-27 13:38:43 +08:00
PlayfieldSkinLayer = drawableRuleset ! = null
2023-07-28 14:48:21 +08:00
? new SkinComponentsContainer ( new SkinComponentsContainerLookup ( SkinComponentsContainerLookup . TargetArea . Playfield , drawableRuleset . Ruleset . RulesetInfo ) ) { AlwaysPresent = true , }
: Empty ( ) ,
2020-10-15 16:11:02 +08:00
topRightElements = new FillFlowContainer
{
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight ,
2022-06-15 00:04:43 +08:00
AlwaysPresent = true ,
2020-10-15 16:11:02 +08:00
Margin = new MarginPadding ( 10 ) ,
Spacing = new Vector2 ( 10 ) ,
AutoSizeAxes = Axes . Both ,
Direction = FillDirection . Vertical ,
Children = new Drawable [ ]
{
2019-01-17 15:00:11 +08:00
ModDisplay = CreateModsContainer ( ) ,
2019-12-12 13:19:04 +08:00
PlayerSettingsOverlay = CreatePlayerSettingsOverlay ( ) ,
2019-01-17 15:00:11 +08:00
}
} ,
2020-10-14 17:51:53 +08:00
bottomRightElements = new FillFlowContainer
2017-04-03 16:41:17 +08:00
{
2019-01-17 15:00:11 +08:00
Anchor = Anchor . BottomRight ,
Origin = Anchor . BottomRight ,
2020-10-15 16:11:02 +08:00
Margin = new MarginPadding ( 10 ) ,
Spacing = new Vector2 ( 10 ) ,
2019-01-17 15:00:11 +08:00
AutoSizeAxes = Axes . Both ,
2020-10-15 15:56:05 +08:00
LayoutDuration = FADE_DURATION / 2 ,
LayoutEasing = FADE_EASING ,
2019-01-17 15:00:11 +08:00
Direction = FillDirection . Vertical ,
Children = new Drawable [ ]
2018-05-22 15:45:42 +08:00
{
2019-01-17 15:00:11 +08:00
HoldToQuit = CreateHoldForMenuButton ( ) ,
2018-05-22 15:45:42 +08:00
}
2022-08-09 03:27:46 +08:00
} ,
2022-09-13 17:23:47 +08:00
LeaderboardFlow = new FillFlowContainer
{
AutoSizeAxes = Axes . Both ,
Direction = FillDirection . Vertical ,
2022-09-13 17:42:57 +08:00
Padding = new MarginPadding ( 44 ) , // enough margin to avoid the hit error display
2022-09-13 17:23:47 +08:00
Spacing = new Vector2 ( 5 )
} ,
2019-01-17 15:00:11 +08:00
} ;
2022-09-13 17:12:49 +08:00
2024-05-02 15:36:40 +08:00
hideTargets = new List < Drawable > { mainComponents , topRightElements } ;
2024-01-22 20:45:55 +08:00
if ( rulesetComponents ! = null )
hideTargets . Add ( rulesetComponents ) ;
2022-09-13 17:23:47 +08:00
2022-09-13 18:57:40 +08:00
if ( ! alwaysShowLeaderboard )
2022-09-13 17:23:47 +08:00
hideTargets . Add ( LeaderboardFlow ) ;
2019-05-09 17:06:11 +08:00
}
2018-04-13 17:19:50 +08:00
2019-05-09 17:06:11 +08:00
[BackgroundDependencyLoader(true)]
2022-08-11 17:58:30 +08:00
private void load ( OsuConfigManager config , INotificationOverlay notificationOverlay )
2019-05-09 17:06:11 +08:00
{
2019-12-12 15:09:42 +08:00
if ( drawableRuleset ! = null )
{
BindDrawableRuleset ( drawableRuleset ) ;
}
2018-04-13 17:19:50 +08:00
2019-04-08 17:32:05 +08:00
ModDisplay . Current . Value = mods ;
2018-04-13 17:19:50 +08:00
2020-07-22 11:41:06 +08:00
configVisibilityMode = config . GetBindable < HUDVisibilityMode > ( OsuSetting . HUDVisibilityMode ) ;
2023-07-29 02:39:41 +08:00
configLeaderboardVisibility = config . GetBindable < bool > ( OsuSetting . GameplayLeaderboard ) ;
2023-07-05 23:46:28 +08:00
configSettingsOverlay = config . GetBindable < bool > ( OsuSetting . ReplaySettingsOverlay ) ;
2019-12-12 14:05:29 +08:00
2020-07-22 11:41:06 +08:00
if ( configVisibilityMode . Value = = HUDVisibilityMode . Never & & ! hasShownNotificationOnce )
2019-12-12 14:05:29 +08:00
{
hasShownNotificationOnce = true ;
notificationOverlay ? . Post ( new SimpleNotification
{
2023-01-14 07:30:10 +08:00
Text = NotificationsStrings . ScoreOverlayDisabled ( config . LookupKeyBindings ( GlobalAction . ToggleInGameInterface ) )
2019-12-12 14:05:29 +08:00
} ) ;
}
// start all elements hidden
hideTargets . ForEach ( d = > d . Hide ( ) ) ;
}
2022-05-11 15:09:16 +08:00
public override void Hide ( ) = >
throw new InvalidOperationException ( $"{nameof(HUDOverlay)} should not be hidden as it will remove the ability of a user to quit. Use {nameof(ShowHud)} instead." ) ;
2019-12-12 14:05:29 +08:00
protected override void LoadComplete ( )
{
base . LoadComplete ( ) ;
2020-10-15 15:56:05 +08:00
ShowHud . BindValueChanged ( visible = > hideTargets . ForEach ( d = > d . FadeTo ( visible . NewValue ? 1 : 0 , FADE_DURATION , FADE_EASING ) ) ) ;
2018-04-13 17:19:50 +08:00
2022-05-11 15:09:16 +08:00
holdingForHUD . BindValueChanged ( _ = > updateVisibility ( ) ) ;
2022-04-26 10:19:19 +08:00
IsPlaying . BindValueChanged ( _ = > updateVisibility ( ) ) ;
2023-07-05 23:46:28 +08:00
configVisibilityMode . BindValueChanged ( _ = > updateVisibility ( ) ) ;
configSettingsOverlay . BindValueChanged ( _ = > updateVisibility ( ) ) ;
2018-04-13 17:19:50 +08:00
2023-07-05 23:46:28 +08:00
replayLoaded . BindValueChanged ( e = >
{
if ( e . NewValue )
{
ModDisplay . FadeIn ( 200 ) ;
InputCountController . Margin = new MarginPadding ( 10 ) { Bottom = 30 } ;
}
else
{
ModDisplay . Delay ( 2000 ) . FadeOut ( 200 ) ;
InputCountController . Margin = new MarginPadding ( 10 ) ;
}
updateVisibility ( ) ;
} , true ) ;
2018-01-17 20:52:57 +08:00
}
2018-04-13 17:19:50 +08:00
2020-10-14 17:51:53 +08:00
protected override void Update ( )
{
base . Update ( ) ;
2020-10-15 16:11:02 +08:00
2023-07-29 07:07:08 +08:00
if ( drawableRuleset ! = null )
{
Quad playfieldScreenSpaceDrawQuad = drawableRuleset . Playfield . SkinnableComponentScreenSpaceDrawQuad ;
2023-07-28 14:48:21 +08:00
2024-05-27 13:38:43 +08:00
PlayfieldSkinLayer . Position = ToLocalSpace ( playfieldScreenSpaceDrawQuad . TopLeft ) ;
PlayfieldSkinLayer . Width = ( ToLocalSpace ( playfieldScreenSpaceDrawQuad . TopRight ) - ToLocalSpace ( playfieldScreenSpaceDrawQuad . TopLeft ) ) . Length ;
PlayfieldSkinLayer . Height = ( ToLocalSpace ( playfieldScreenSpaceDrawQuad . BottomLeft ) - ToLocalSpace ( playfieldScreenSpaceDrawQuad . TopLeft ) ) . Length ;
PlayfieldSkinLayer . Rotation = drawableRuleset . Playfield . Rotation ;
2023-07-29 07:07:08 +08:00
}
2023-07-28 14:48:21 +08:00
2022-09-13 17:42:57 +08:00
float? lowestTopScreenSpaceLeft = null ;
float? lowestTopScreenSpaceRight = null ;
2021-05-17 17:26:30 +08:00
Vector2 ? highestBottomScreenSpace = null ;
2021-05-11 11:42:32 +08:00
2024-02-26 09:04:39 +08:00
processDrawables ( mainComponents ) ;
2024-01-18 14:44:27 +08:00
if ( rulesetComponents ! = null )
2024-02-26 09:04:39 +08:00
processDrawables ( rulesetComponents ) ;
2024-01-18 14:44:27 +08:00
if ( lowestTopScreenSpaceRight . HasValue )
topRightElements . Y = MathHelper . Clamp ( ToLocalSpace ( new Vector2 ( 0 , lowestTopScreenSpaceRight . Value ) ) . Y , 0 , DrawHeight - topRightElements . DrawHeight ) ;
else
topRightElements . Y = 0 ;
if ( lowestTopScreenSpaceLeft . HasValue )
LeaderboardFlow . Y = MathHelper . Clamp ( ToLocalSpace ( new Vector2 ( 0 , lowestTopScreenSpaceLeft . Value ) ) . Y , 0 , DrawHeight - LeaderboardFlow . DrawHeight ) ;
else
LeaderboardFlow . Y = 0 ;
if ( highestBottomScreenSpace . HasValue )
bottomRightElements . Y = BottomScoringElementsHeight = - MathHelper . Clamp ( DrawHeight - ToLocalSpace ( highestBottomScreenSpace . Value ) . Y , 0 , DrawHeight - bottomRightElements . DrawHeight ) ;
else
bottomRightElements . Y = 0 ;
2024-02-26 09:04:39 +08:00
void processDrawables ( SkinComponentsContainer components )
{
// Avoid using foreach due to missing GetEnumerator implementation.
// See https://github.com/ppy/osu-framework/blob/e10051e6643731e393b09de40a3a3d209a545031/osu.Framework/Bindables/IBindableList.cs#L41-L44.
for ( int i = 0 ; i < components . Components . Count ; i + + )
processDrawable ( components . Components [ i ] ) ;
}
2024-01-26 11:55:36 +08:00
void processDrawable ( ISerialisableDrawable element )
2021-05-11 11:42:32 +08:00
{
2024-01-26 11:55:36 +08:00
// Cast can be removed when IDrawable interface includes Anchor / RelativeSizeAxes.
Drawable drawable = ( Drawable ) element ;
2022-09-19 23:08:06 +08:00
// for now align some top components with the bottom-edge of the lowest top-anchored hud element.
2024-01-26 11:55:36 +08:00
if ( drawable . Anchor . HasFlagFast ( Anchor . y0 ) )
2021-05-17 17:26:30 +08:00
{
// health bars are excluded for the sake of hacky legacy skins which extend the health bar to take up the full screen area.
if ( element is LegacyHealthDisplay )
2024-01-18 14:44:27 +08:00
return ;
2020-10-15 17:30:44 +08:00
2024-01-26 11:55:36 +08:00
float bottom = drawable . ScreenSpaceDrawQuad . BottomRight . Y ;
2022-09-13 17:42:57 +08:00
2024-01-26 11:55:36 +08:00
bool isRelativeX = drawable . RelativeSizeAxes = = Axes . X ;
2022-09-13 17:42:57 +08:00
2024-01-26 11:55:36 +08:00
if ( drawable . Anchor . HasFlagFast ( Anchor . TopRight ) | | isRelativeX )
2022-09-13 17:42:57 +08:00
{
if ( lowestTopScreenSpaceRight = = null | | bottom > lowestTopScreenSpaceRight . Value )
lowestTopScreenSpaceRight = bottom ;
}
2024-01-26 11:55:36 +08:00
if ( drawable . Anchor . HasFlagFast ( Anchor . TopLeft ) | | isRelativeX )
2022-09-13 17:42:57 +08:00
{
if ( lowestTopScreenSpaceLeft = = null | | bottom > lowestTopScreenSpaceLeft . Value )
lowestTopScreenSpaceLeft = bottom ;
}
2021-05-17 17:26:30 +08:00
}
2021-05-23 21:22:51 +08:00
// and align bottom-right components with the top-edge of the highest bottom-anchored hud element.
2024-01-26 11:55:36 +08:00
else if ( drawable . Anchor . HasFlagFast ( Anchor . BottomRight ) | | ( drawable . Anchor . HasFlagFast ( Anchor . y2 ) & & drawable . RelativeSizeAxes = = Axes . X ) )
2021-05-17 17:26:30 +08:00
{
var topLeft = element . ScreenSpaceDrawQuad . TopLeft ;
if ( highestBottomScreenSpace = = null | | topLeft . Y < highestBottomScreenSpace . Value . Y )
highestBottomScreenSpace = topLeft ;
}
2021-05-11 11:42:32 +08:00
}
2020-10-14 17:51:53 +08:00
}
2020-07-22 11:41:06 +08:00
private void updateVisibility ( )
{
if ( ShowHud . Disabled )
return ;
2022-05-11 15:09:16 +08:00
if ( holdingForHUD . Value )
2020-10-30 13:19:40 +08:00
{
ShowHud . Value = true ;
return ;
}
2023-07-05 23:46:28 +08:00
if ( configSettingsOverlay . Value & & replayLoaded . Value )
PlayerSettingsOverlay . Show ( ) ;
else
PlayerSettingsOverlay . Hide ( ) ;
2020-07-22 11:41:06 +08:00
switch ( configVisibilityMode . Value )
{
case HUDVisibilityMode . Never :
ShowHud . Value = false ;
break ;
2020-10-20 13:19:04 +08:00
case HUDVisibilityMode . HideDuringGameplay :
// always show during replay as we want the seek bar to be visible.
2022-04-26 10:19:19 +08:00
ShowHud . Value = replayLoaded . Value | | ! IsPlaying . Value ;
2020-10-20 13:19:04 +08:00
break ;
2020-07-22 11:41:06 +08:00
case HUDVisibilityMode . Always :
ShowHud . Value = true ;
break ;
}
}
2019-03-19 22:44:15 +08:00
protected virtual void BindDrawableRuleset ( DrawableRuleset drawableRuleset )
2017-03-11 13:27:18 +08:00
{
2023-06-25 21:04:39 +08:00
if ( drawableRuleset is ICanAttachHUDPieces attachTarget )
{
2023-06-27 01:27:42 +08:00
attachTarget . Attach ( InputCountController ) ;
2023-06-27 15:38:46 +08:00
attachTarget . Attach ( clicksPerSecondController ) ;
2023-06-25 21:04:39 +08:00
}
2018-04-13 17:19:50 +08:00
2019-03-19 22:44:15 +08:00
replayLoaded . BindTo ( drawableRuleset . HasReplayLoaded ) ;
2017-03-11 13:27:18 +08:00
}
2018-04-13 17:19:50 +08:00
2021-05-06 14:16:16 +08:00
protected FailingLayer CreateFailingLayer ( ) = > new FailingLayer
2020-06-27 01:22:30 +08:00
{
2021-12-10 13:15:00 +08:00
ShowHealth = { BindTarget = ShowHealthBar }
2020-06-27 01:22:30 +08:00
} ;
2020-04-09 13:31:25 +08:00
2021-05-06 14:16:16 +08:00
protected HoldForMenuButton CreateHoldForMenuButton ( ) = > new HoldForMenuButton
2018-04-21 23:24:31 +08:00
{
Anchor = Anchor . BottomRight ,
Origin = Anchor . BottomRight ,
} ;
2021-05-06 14:16:16 +08:00
protected ModDisplay CreateModsContainer ( ) = > new ModDisplay
2017-06-05 16:15:04 +08:00
{
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight ,
} ;
2018-04-13 17:19:50 +08:00
2021-05-06 14:16:16 +08:00
protected PlayerSettingsOverlay CreatePlayerSettingsOverlay ( ) = > new PlayerSettingsOverlay ( ) ;
2018-04-13 17:19:50 +08:00
2021-09-16 17:26:12 +08:00
public bool OnPressed ( KeyBindingPressEvent < GlobalAction > e )
2020-10-30 13:19:40 +08:00
{
2021-11-18 11:35:47 +08:00
if ( e . Repeat )
return false ;
2021-09-16 17:26:12 +08:00
switch ( e . Action )
2020-10-30 13:19:40 +08:00
{
2023-07-06 00:00:41 +08:00
case GlobalAction . ToggleReplaySettings :
configSettingsOverlay . Value = ! configSettingsOverlay . Value ;
return true ;
2020-10-30 13:19:40 +08:00
case GlobalAction . HoldForHUD :
2022-05-11 15:09:16 +08:00
holdingForHUD . Value = true ;
2020-10-30 13:19:40 +08:00
return true ;
2020-11-30 09:59:02 +08:00
case GlobalAction . ToggleInGameInterface :
switch ( configVisibilityMode . Value )
{
case HUDVisibilityMode . Never :
configVisibilityMode . Value = HUDVisibilityMode . HideDuringGameplay ;
break ;
case HUDVisibilityMode . HideDuringGameplay :
configVisibilityMode . Value = HUDVisibilityMode . Always ;
break ;
case HUDVisibilityMode . Always :
configVisibilityMode . Value = HUDVisibilityMode . Never ;
break ;
}
2020-12-01 13:00:54 +08:00
2020-11-30 09:59:02 +08:00
return true ;
2023-07-29 02:39:41 +08:00
case GlobalAction . ToggleInGameLeaderboard :
configLeaderboardVisibility . Value = ! configLeaderboardVisibility . Value ;
return true ;
2020-10-30 13:19:40 +08:00
}
return false ;
}
2021-09-16 17:26:12 +08:00
public void OnReleased ( KeyBindingReleaseEvent < GlobalAction > e )
2020-10-30 13:19:40 +08:00
{
2021-09-16 17:26:12 +08:00
switch ( e . Action )
2020-10-30 13:19:40 +08:00
{
case GlobalAction . HoldForHUD :
2022-05-11 15:09:16 +08:00
holdingForHUD . Value = false ;
2020-10-30 13:19:40 +08:00
break ;
}
}
2022-02-03 13:50:40 +08:00
2023-02-16 18:20:06 +08:00
private partial class HUDComponentsContainer : SkinComponentsContainer
2022-02-03 13:50:40 +08:00
{
private Bindable < ScoringMode > scoringMode ;
[Resolved]
private OsuConfigManager config { get ; set ; }
2023-02-17 14:00:57 +08:00
public HUDComponentsContainer ( [ CanBeNull ] RulesetInfo ruleset = null )
2023-02-16 18:20:06 +08:00
: base ( new SkinComponentsContainerLookup ( SkinComponentsContainerLookup . TargetArea . MainHUDComponents , ruleset ) )
2022-02-03 13:50:40 +08:00
{
RelativeSizeAxes = Axes . Both ;
}
protected override void LoadComplete ( )
{
base . LoadComplete ( ) ;
// When the scoring mode changes, relative positions of elements may change (see DefaultSkin.GetDrawableComponent).
// This is a best effort implementation for cases where users haven't customised layouts.
scoringMode = config . GetBindable < ScoringMode > ( OsuSetting . ScoreDisplayMode ) ;
2022-06-24 20:25:23 +08:00
scoringMode . BindValueChanged ( _ = > Reload ( ) ) ;
2022-02-03 13:50:40 +08:00
}
}
2017-03-11 13:27:18 +08:00
}
}