// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { /// /// A layer that will show a loading spinner and completely block input to an area. /// Also optionally dims target elements. /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance. /// public partial class LoadingLayer : LoadingSpinner, IKeyBindingHandler { /// /// Whether to block positional input of components behind the loading layer. /// Defaults to true. /// public bool BlockPositionalInput { get; init; } = true; /// /// Whether to block all keyboard input. Includes global actions. /// Defaults to false. /// public bool BlockNonPositionalInput { get; init; } /// /// Construct a new loading spinner. /// /// Whether the full background area should be dimmed while loading. /// Whether the spinner should have a surrounding black box for visibility. public LoadingLayer(bool dimBackground = false, bool withBox = true) : base(withBox) { RelativeSizeAxes = Axes.Both; Size = new Vector2(1); MainContents.RelativeSizeAxes = Axes.None; if (dimBackground) { AddInternal(new Box { Depth = float.MaxValue, Colour = Color4.Black, Alpha = 0.5f, RelativeSizeAxes = Axes.Both, }); } } public override bool HandleNonPositionalInput => BlockNonPositionalInput; protected override bool Handle(UIEvent e) { if (!BlockPositionalInput) return false; switch (e) { // blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer. case ScrollEvent: return false; // blocking touch events causes the ISourcedFromTouch versions to not be fired, potentially impeding behaviour of drawables *above* the loading layer that may utilise these. // note that this will not work well if touch handling elements are beneath this loading layer (something to consider for the future). case TouchEvent: return false; } return true; } protected override void Update() { base.Update(); MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 20, 80)); } public bool OnPressed(KeyBindingPressEvent e) => BlockNonPositionalInput; public void OnReleased(KeyBindingReleaseEvent e) { } } }