Code/SboxSuperuser/Components/SuperuserVotePanel.cs

A scene component for a vote UI. While the VoteClientSystem has a running vote, it reads F-key presses as ballots, draws the vote panel through VotePanelRenderer, and sends the clicked or keyed choice via Superuser.CastVote, skipping input while the chat box is open.

using Sandbox;
using SboxSuperuser.Systems;

namespace SboxSuperuser.Components;

/// <summary>
/// Superuser's vote panel: slides in from the left while a vote runs, takes F1, F2 and so on (or a click) as
/// ballots, and lights up each voter as they choose. Leave it out of the scene to draw your own from
/// Superuser.CurrentVote and IVoteEvent, sending ballots with Superuser.CastVote.
/// </summary>
[Title( "Superuser Vote Panel" ), Category( "Superuser" ), Icon( "how_to_vote" )]
public sealed class SuperuserVotePanel : Component
{
	private readonly UI.VotePanelRenderer _renderer = new();

	protected override void OnUpdate()
	{
		if ( Scene.GetSystem<VoteClientSystem>() is not { Vote: { } vote } votes || Scene.Camera is not { } camera ) return;
		if ( !vote.Finished && !ChatOpen() )
			for ( var option = 0; option < vote.Options.Length; option++ )
				if ( Input.Keyboard.Pressed( UI.VotePanelRenderer.Keys[ option ] ) ) Superuser.CastVote( option );
		var clicked = _renderer.Draw( camera, vote, votes.SinceStarted, votes.SinceFinished );
		if ( clicked is { } choice && !vote.Finished ) Superuser.CastVote( choice );
	}

	// Typing in chat shouldn't vote; F keys still work while the chat box is closed.
	private bool ChatOpen() => Scene.GetSystem<ChatBoxSystem>()?.IsOpen == true;
}