// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Footer; namespace osu.Game.Overlays.Mods { /// /// A sheared overlay which provides a header and basic animations. /// Exposes and as valid targets for content. /// public abstract partial class ShearedOverlayContainer : OsuFocusedOverlayContainer { public const float PADDING = 14; [Cached] public readonly OverlayColourProvider ColourProvider; /// /// The overlay's header. /// protected ShearedOverlayHeader Header { get; private set; } = null!; /// /// The overlay's footer. /// protected Container Footer { get; private set; } = null!; [Resolved] private ScreenFooter? footer { get; set; } /// /// A container containing all content, including the header and footer. /// May be used for overlay-wide animations. /// protected Container TopLevelContent { get; private set; } = null!; /// /// A container for content that is to be displayed between the header and footer. /// protected Container MainAreaContent { get; private set; } = null!; /// /// A container for content that is to be displayed inside the footer. /// protected Container FooterContent { get; private set; } = null!; protected override bool StartHidden => true; protected override bool BlockNonPositionalInput => true; // ShearedOverlayContainers are placed at a layer within the screen container as they rely on ScreenFooter which must be placed there. // Therefore, dimming must be managed locally, since DimMainContent dims the entire screen layer. protected sealed override bool DimMainContent => false; protected ShearedOverlayContainer(OverlayColourScheme colourScheme) { RelativeSizeAxes = Axes.Both; ColourProvider = new OverlayColourProvider(colourScheme); } [BackgroundDependencyLoader] private void load() { Child = TopLevelContent = new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = ColourProvider.Background6.Opacity(0.75f), }, Header = new ShearedOverlayHeader { Anchor = Anchor.TopCentre, Depth = float.MinValue, Origin = Anchor.TopCentre, Close = Hide }, MainAreaContent = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = ShearedOverlayHeader.HEIGHT, Bottom = ScreenFooter.HEIGHT + PADDING, } }, } }; } /// /// Creates content to be displayed on the game-wide footer. /// public virtual VisibilityContainer? CreateFooterContent() => null; /// /// Invoked when the back button in the footer is pressed. /// /// Whether the back button should not close the overlay. public virtual bool OnBackButton() => false; protected override bool OnClick(ClickEvent e) { if (State.Value == Visibility.Visible) { Hide(); return true; } return base.OnClick(e); } private IDisposable? activeOverlayRegistration; private bool hideFooterOnPopOut; protected override void PopIn() { const double fade_in_duration = 400; this.FadeIn(fade_in_duration, Easing.OutQuint); Header.MoveToY(0, fade_in_duration, Easing.OutQuint); if (footer != null) { activeOverlayRegistration = footer.RegisterActiveOverlayContainer(this); if (footer.State.Value == Visibility.Hidden) { footer.Show(); hideFooterOnPopOut = true; } } } protected override void PopOut() { const double fade_out_duration = 500; base.PopOut(); this.FadeOut(fade_out_duration, Easing.OutQuint); Header.MoveToY(-Header.DrawHeight, fade_out_duration, Easing.OutQuint); if (footer != null) { activeOverlayRegistration?.Dispose(); activeOverlayRegistration = null; if (hideFooterOnPopOut) { footer.Hide(); hideFooterOnPopOut = false; } } } } }