2022-12-01 20:13:37 +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.
using osu.Framework.Allocation ;
2022-12-03 01:44:21 +08:00
using osu.Framework.Bindables ;
2022-12-02 05:07:28 +08:00
using osu.Framework.Extensions.Color4Extensions ;
2022-12-01 20:13:37 +08:00
using osu.Framework.Graphics ;
2024-05-12 08:55:18 +08:00
using osu.Framework.Graphics.Colour ;
2022-12-01 20:13:37 +08:00
using osu.Framework.Graphics.Containers ;
2022-12-01 22:34:09 +08:00
using osu.Framework.Graphics.Effects ;
2022-12-01 20:13:37 +08:00
using osu.Framework.Graphics.Shapes ;
2022-12-01 22:34:09 +08:00
using osu.Framework.Graphics.Sprites ;
2022-12-01 20:13:37 +08:00
using osu.Framework.Input.Bindings ;
using osu.Framework.Input.Events ;
2022-12-01 23:29:52 +08:00
using osu.Framework.Localisation ;
using osu.Game.Graphics ;
2022-12-01 20:13:37 +08:00
using osu.Game.Graphics.Containers ;
2022-12-01 22:34:09 +08:00
using osu.Game.Graphics.Sprites ;
2022-12-01 20:13:37 +08:00
using osu.Game.Input.Bindings ;
using osu.Game.Overlays ;
using osuTK ;
2023-02-03 15:24:19 +08:00
using osuTK.Graphics ;
2022-12-01 20:13:37 +08:00
2024-05-16 09:36:14 +08:00
namespace osu.Game.Screens.Footer
2022-12-01 20:13:37 +08:00
{
2024-05-16 09:36:14 +08:00
public partial class ScreenFooterButton : OsuClickableContainer , IKeyBindingHandler < GlobalAction >
2022-12-01 20:13:37 +08:00
{
2024-05-16 12:27:54 +08:00
private const float shear = OsuGame . SHEAR ;
2022-12-01 20:13:37 +08:00
2024-05-10 11:47:48 +08:00
protected const int CORNER_RADIUS = 10 ;
2024-06-27 13:15:12 +08:00
protected const int BUTTON_HEIGHT = 75 ;
protected const int BUTTON_WIDTH = 116 ;
2024-05-08 08:58:10 +08:00
2022-12-03 01:44:21 +08:00
public Bindable < Visibility > OverlayState = new Bindable < Visibility > ( ) ;
2024-05-16 10:03:34 +08:00
protected static readonly Vector2 BUTTON_SHEAR = new Vector2 ( shear , 0 ) ;
2022-12-01 22:34:09 +08:00
2023-02-14 05:17:02 +08:00
[Resolved]
private OverlayColourProvider colourProvider { get ; set ; } = null ! ;
2022-12-01 20:13:37 +08:00
2022-12-01 22:34:09 +08:00
private Colour4 buttonAccentColour ;
2024-06-29 15:19:58 +08:00
public Colour4 AccentColour
2022-12-01 22:34:09 +08:00
{
set
{
buttonAccentColour = value ;
bar . Colour = buttonAccentColour ;
icon . Colour = buttonAccentColour ;
}
}
2024-06-29 15:19:58 +08:00
public IconUsage Icon
2022-12-01 22:34:09 +08:00
{
set = > icon . Icon = value ;
}
2024-05-16 11:23:07 +08:00
public LocalisableString Text
2022-12-01 22:34:09 +08:00
{
set = > text . Text = value ;
}
2022-12-19 23:35:20 +08:00
private readonly SpriteText text ;
private readonly SpriteIcon icon ;
protected Container TextContainer ;
private readonly Box bar ;
private readonly Box backgroundBox ;
2024-05-12 08:55:18 +08:00
private readonly Box glowBox ;
2024-05-10 13:24:39 +08:00
private readonly Box flashLayer ;
2022-12-19 23:35:20 +08:00
2024-05-16 11:23:07 +08:00
public readonly OverlayContainer ? Overlay ;
public ScreenFooterButton ( OverlayContainer ? overlay = null )
2022-12-01 20:13:37 +08:00
{
2024-05-16 11:23:07 +08:00
Overlay = overlay ;
2024-05-08 08:58:10 +08:00
Size = new Vector2 ( BUTTON_WIDTH , BUTTON_HEIGHT ) ;
2024-06-08 03:07:37 +08:00
Children = new Drawable [ ]
2022-12-01 20:13:37 +08:00
{
2024-06-08 03:07:37 +08:00
new Container
2022-12-01 20:13:37 +08:00
{
2024-06-08 03:07:37 +08:00
EdgeEffect = new EdgeEffectParameters
2024-05-08 08:58:10 +08:00
{
2024-06-08 03:07:37 +08:00
Type = EdgeEffectType . Shadow ,
Radius = 4 ,
// Figma says 50% opacity, but it does not match up visually if taken at face value, and looks bad.
Colour = Colour4 . Black . Opacity ( 0.25f ) ,
Offset = new Vector2 ( 0 , 2 ) ,
} ,
Shear = BUTTON_SHEAR ,
Masking = true ,
CornerRadius = CORNER_RADIUS ,
RelativeSizeAxes = Axes . Both ,
Children = new Drawable [ ]
{
backgroundBox = new Box
2024-05-16 11:23:07 +08:00
{
2024-06-08 03:07:37 +08:00
RelativeSizeAxes = Axes . Both
2024-05-16 11:23:07 +08:00
} ,
2024-06-08 03:07:37 +08:00
glowBox = new Box
2022-12-01 23:29:52 +08:00
{
2024-06-08 03:07:37 +08:00
RelativeSizeAxes = Axes . Both
} ,
// For elements that should not be sheared.
new Container
{
Anchor = Anchor . CentreLeft ,
Origin = Anchor . CentreLeft ,
Shear = - BUTTON_SHEAR ,
RelativeSizeAxes = Axes . Both ,
Children = new Drawable [ ]
2022-12-01 23:29:52 +08:00
{
2024-06-08 03:07:37 +08:00
TextContainer = new Container
2024-05-08 08:58:10 +08:00
{
2024-06-08 03:07:37 +08:00
Anchor = Anchor . TopCentre ,
Origin = Anchor . TopCentre ,
2024-06-27 13:15:12 +08:00
Y = 35 ,
2024-06-08 03:07:37 +08:00
AutoSizeAxes = Axes . Both ,
Child = text = new OsuSpriteText
2024-05-16 11:23:07 +08:00
{
2024-06-27 13:15:12 +08:00
Font = OsuFont . TorusAlternate . With ( size : 16 ) ,
2024-06-08 03:07:37 +08:00
AlwaysPresent = true
}
} ,
icon = new SpriteIcon
2024-05-16 11:23:07 +08:00
{
2024-06-27 13:15:12 +08:00
Y = 10 ,
Size = new Vector2 ( 16 ) ,
2024-06-08 03:07:37 +08:00
Anchor = Anchor . TopCentre ,
Origin = Anchor . TopCentre
} ,
}
} ,
new Container
{
Shear = - BUTTON_SHEAR ,
Anchor = Anchor . BottomCentre ,
Origin = Anchor . Centre ,
Y = - CORNER_RADIUS ,
2024-06-27 13:15:12 +08:00
Size = new Vector2 ( 100 , 5 ) ,
2024-06-08 03:07:37 +08:00
Masking = true ,
CornerRadius = 3 ,
Child = bar = new Box
2024-05-16 11:23:07 +08:00
{
RelativeSizeAxes = Axes . Both ,
2024-06-08 03:07:37 +08:00
}
2024-05-16 11:23:07 +08:00
} ,
2024-06-08 03:07:37 +08:00
flashLayer = new Box
{
RelativeSizeAxes = Axes . Both ,
Colour = Colour4 . White . Opacity ( 0.9f ) ,
Blending = BlendingParameters . Additive ,
Alpha = 0 ,
} ,
} ,
2024-05-16 11:23:07 +08:00
}
2022-12-01 20:13:37 +08:00
} ;
}
2022-12-02 05:31:14 +08:00
protected override void LoadComplete ( )
2022-12-01 23:29:52 +08:00
{
2022-12-02 05:31:14 +08:00
base . LoadComplete ( ) ;
2022-12-19 18:30:23 +08:00
2024-05-16 11:23:07 +08:00
if ( Overlay ! = null )
OverlayState . BindTo ( Overlay . State ) ;
2024-06-29 14:59:40 +08:00
OverlayState . BindValueChanged ( _ = > UpdateDisplay ( ) ) ;
Enabled . BindValueChanged ( _ = > UpdateDisplay ( ) , true ) ;
2023-02-03 15:25:54 +08:00
FinishTransforms ( true ) ;
2022-12-01 23:29:52 +08:00
}
2024-06-29 15:06:49 +08:00
// use Content for tracking input as some buttons might be temporarily hidden with DisappearToBottom, and they become hidden by moving Content away from screen.
public override bool ReceivePositionalInputAt ( Vector2 screenSpacePos ) = > Content . ReceivePositionalInputAt ( screenSpacePos ) ;
2022-12-02 05:31:14 +08:00
public GlobalAction ? Hotkey ;
2024-05-10 13:24:39 +08:00
protected override bool OnClick ( ClickEvent e )
2022-12-01 20:13:37 +08:00
{
2024-05-10 13:24:39 +08:00
if ( Enabled . Value )
Flash ( ) ;
2022-12-01 23:29:52 +08:00
2024-05-10 13:24:39 +08:00
return base . OnClick ( e ) ;
2023-02-03 15:24:19 +08:00
}
2024-05-10 13:24:39 +08:00
protected virtual void Flash ( ) = > flashLayer . FadeOutFromOne ( 800 , Easing . OutQuint ) ;
protected override bool OnHover ( HoverEvent e )
2023-02-03 15:24:19 +08:00
{
2024-06-29 14:59:40 +08:00
UpdateDisplay ( ) ;
2024-05-10 13:24:39 +08:00
return true ;
2023-02-03 15:24:19 +08:00
}
2024-06-29 14:59:40 +08:00
protected override void OnHoverLost ( HoverLostEvent e ) = > UpdateDisplay ( ) ;
2022-12-01 23:29:52 +08:00
public virtual bool OnPressed ( KeyBindingPressEvent < GlobalAction > e )
{
2022-12-19 23:35:20 +08:00
if ( e . Action ! = Hotkey | | e . Repeat ) return false ;
2022-12-01 23:29:52 +08:00
2022-12-19 23:35:20 +08:00
TriggerClick ( ) ;
return true ;
2022-12-01 20:13:37 +08:00
}
2022-12-01 23:29:52 +08:00
public virtual void OnReleased ( KeyBindingReleaseEvent < GlobalAction > e ) { }
2022-12-02 05:07:28 +08:00
2024-06-29 14:59:40 +08:00
public void UpdateDisplay ( )
2022-12-02 05:07:28 +08:00
{
2024-05-10 13:24:39 +08:00
Color4 backgroundColour = OverlayState . Value = = Visibility . Visible ? buttonAccentColour : colourProvider . Background3 ;
Color4 textColour = OverlayState . Value = = Visibility . Visible ? colourProvider . Background6 : colourProvider . Content1 ;
Color4 accentColour = OverlayState . Value = = Visibility . Visible ? colourProvider . Background6 : buttonAccentColour ;
2023-02-03 15:24:19 +08:00
2022-12-02 05:31:14 +08:00
if ( ! Enabled . Value )
2024-05-10 13:24:39 +08:00
backgroundColour = backgroundColour . Darken ( 1f ) ;
else if ( IsHovered )
backgroundColour = backgroundColour . Lighten ( 0.2f ) ;
2022-12-03 01:44:21 +08:00
2024-05-10 13:24:39 +08:00
backgroundBox . FadeColour ( backgroundColour , 150 , Easing . OutQuint ) ;
2023-02-03 15:24:19 +08:00
2024-05-10 13:24:39 +08:00
if ( ! Enabled . Value )
textColour = textColour . Opacity ( 0.6f ) ;
2022-12-03 01:44:21 +08:00
2024-05-10 13:24:39 +08:00
text . FadeColour ( textColour , 150 , Easing . OutQuint ) ;
icon . FadeColour ( accentColour , 150 , Easing . OutQuint ) ;
bar . FadeColour ( accentColour , 150 , Easing . OutQuint ) ;
2022-12-03 01:44:21 +08:00
2024-05-12 12:58:43 +08:00
glowBox . FadeColour ( ColourInfo . GradientVertical ( buttonAccentColour . Opacity ( 0f ) , buttonAccentColour . Opacity ( 0.2f ) ) , 150 , Easing . OutQuint ) ;
2022-12-02 05:07:28 +08:00
}
2024-06-08 03:07:37 +08:00
public void AppearFromLeft ( double delay )
{
2024-06-30 11:15:50 +08:00
Content . FinishTransforms ( ) ;
2024-06-08 03:07:37 +08:00
Content . MoveToX ( - 300f )
. FadeOut ( )
. Delay ( delay )
. MoveToX ( 0f , 240 , Easing . OutCubic )
. FadeIn ( 240 , Easing . OutCubic ) ;
}
public void AppearFromBottom ( double delay )
{
2024-06-30 11:15:50 +08:00
Content . FinishTransforms ( ) ;
2024-06-08 03:07:37 +08:00
Content . MoveToY ( 100f )
. FadeOut ( )
. Delay ( delay )
. MoveToY ( 0f , 240 , Easing . OutCubic )
. FadeIn ( 240 , Easing . OutCubic ) ;
}
2024-06-29 13:35:48 +08:00
public void DisappearToRight ( double delay , bool expire )
2024-06-08 03:07:37 +08:00
{
2024-06-30 11:15:50 +08:00
Content . FinishTransforms ( ) ;
2024-06-08 03:07:37 +08:00
Content . Delay ( delay )
. FadeOut ( 240 , Easing . InOutCubic )
. MoveToX ( 300f , 360 , Easing . InOutCubic ) ;
2024-06-29 13:35:48 +08:00
if ( expire )
this . Delay ( Content . LatestTransformEndTime - Time . Current ) . Expire ( ) ;
2024-06-08 03:07:37 +08:00
}
2024-06-29 13:35:48 +08:00
public void DisappearToBottom ( double delay , bool expire )
2024-06-08 03:07:37 +08:00
{
2024-06-30 11:15:50 +08:00
Content . FinishTransforms ( ) ;
2024-06-08 03:07:37 +08:00
Content . Delay ( delay )
. FadeOut ( 240 , Easing . InOutCubic )
. MoveToY ( 100f , 240 , Easing . InOutCubic ) ;
2024-06-29 13:35:48 +08:00
if ( expire )
this . Delay ( Content . LatestTransformEndTime - Time . Current ) . Expire ( ) ;
2024-06-08 03:07:37 +08:00
}
2022-12-01 20:13:37 +08:00
}
}