Code/SboxSuperuser/UI/AdminMenuRenderer.Notices.cs

Partial of the admin menu ImGui renderer that draws transient toast notices. Queues (text, color) pairs with a timestamp and renders the still-visible ones in the bottom-right corner with a fading background, ignoring input. The same notices are also read by the menu bar.

using Sandbox;
using SboxSuperuser.Core.Menu;
using SboxSuperuser.Engine.Vendor.ImGui;

namespace SboxSuperuser.UI;

internal sealed partial class AdminMenuRenderer
{
	private const ImGuiWindowFlags NoticeFlags = ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.AlwaysAutoResize
		| ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoBringToFrontOnFocus;

	private readonly Notices<(string Text, Vector4 Color)> _notices = new();

	/// <summary>Shows a result briefly in the bottom-right corner, as well as on the menu bar.</summary>
	private void Notify( string text, Vector4 color ) => _notices.Add( (text, color), DateTimeOffset.UtcNow );

	private void DrawNotices()
	{
		var visible = _notices.Visible( DateTimeOffset.UtcNow );
		if ( visible.Count == 0 ) return;

		var margin = 16 * Scale;
		ImGui.SetNextWindowPos( new Vector2( Screen.Width - margin, Screen.Height - margin ), ImGuiCond.Always, new Vector2( 1, 1 ) );
		ImGui.SetNextWindowBgAlpha( 0.9f * visible.Max( notice => notice.Opacity ) );
		if ( ImGui.Begin( "##notices", NoticeFlags ) )
		{
			ImGui.PushTextWrapPos( 380 * Scale );
			foreach ( var ((text, color), opacity) in visible )
				ImGui.TextColored( new Vector4( color.x, color.y, color.z, color.w * opacity ), "{0}", text );
			ImGui.PopTextWrapPos();
		}
		ImGui.End();
	}
}