UI/WebLinkLabel.cs
using Sandbox.UI;

namespace BlockParty;

/// <summary>
/// Rich-text label whose anchor opens in the user's web browser. The engine only opens web pages
/// from a rich label's http/https anchor (Label.OnClick) — game code has no browser-open API — so
/// the whole chip is one big anchor glyph. Fixes up the two engine behaviours that don't fit this
/// game: anchor hover stamps Style.Cursor = "pointer" (the real OS hand — everything here uses the
/// blanked cursor names so the software cursor draws instead), and clicks are silent.
/// </summary>
public sealed class WebLinkLabel : Label
{
	// Whether the anchor glyph itself is under the cursor — i.e. whether a click here will actually
	// navigate. A rich label only hit-tests the TEXT, so the ring of label around the glyph is dead
	// space, and the chip this lives in is deliberately bigger than its icon; blipping there promised
	// a navigation that never came.
	private bool _overAnchor;

	protected override void OnMouseMove( MousePanelEvent e )
	{
		// The engine resolves which rich-text span is under the cursor inside its OnMouseMove and
		// publishes that resolution ONLY as Style.Cursor ("pointer" over an <a>, else null), and only
		// on the frames where the hovered span CHANGES. Our own "blank-hand" write below therefore
		// doubles as the sentinel: if it survived the call, the span is the same as last move and the
		// latch still holds. Should the engine ever stop stamping the cursor, this fails QUIET (no
		// blip) rather than wrong (blip with no navigation).
		base.OnMouseMove( e );
		if ( Style.Cursor == "pointer" ) _overAnchor = true;
		else if ( Style.Cursor is null ) _overAnchor = false;

		Style.Cursor = "blank-hand";
	}

	protected override void OnClick( MousePanelEvent e )
	{
		if ( _overAnchor )
			Audio.PlaySfx( SfxType.MenuBlip, 0.7f );

		base.OnClick( e );
	}
}