WalletLcdLine.cs

UI Panel component that renders a single LCD-style text line as a texture fitted into a fixed viewport. It computes a texture via WalletFont.GetLineTexture, picks scale to fit LCD glass constraints, sets panel size and background image, and updates when Text or Small change.

File Access
namespace NoChillquarium;

/// <summary>
/// Full LCD text line as one texture, fitted into a fixed viewport.
/// Device size never grows — long values scale down inside the glass.
/// </summary>
[Library( "walletlcd" )]
public class WalletLcdLine : Panel
{
	string _text = "";
	bool _small;
	string _appliedKey;

	public string Text
	{
		get => _text;
		set
		{
			var v = value ?? "";
			if ( string.Equals( _text, v, StringComparison.Ordinal ) )
				return;
			_text = v;
			Apply();
		}
	}

	public bool Small
	{
		get => _small;
		set
		{
			if ( _small == value )
				return;
			_small = value;
			Apply();
		}
	}

	public WalletLcdLine()
	{
		AddClass( "wallet-lcd-line" );
	}

	public override void Tick()
	{
		base.Tick();
		var want = _text ?? "";
		var key = (_small ? "s:" : "b:") + want;
		if ( _appliedKey != key )
			Apply();
	}

	void Apply()
	{
		var maxChars = _small ? WalletFont.MaxRateChars : WalletFont.MaxBalanceChars;
		var tex = WalletFont.GetLineTexture( _text, maxChars );
		var key = (_small ? "s:" : "b:") + (_text ?? "");

		if ( tex is null )
		{
			Style.BackgroundImage = null;
			_appliedKey = null;
			return;
		}

		// Preferred pixel scale (crisp), then shrink to fit fixed LCD glass.
		// Rate line stays much smaller than the balance.
		var prefer = _small ? 0.8f : 2f;
		var maxW = WalletFont.LcdGlassInnerW;
		var maxH = _small ? WalletFont.LcdRateMaxH : WalletFont.LcdBalanceMaxH;
		var floor = _small ? 0.5f : 0.9f;

		var scale = prefer;
		if ( tex.Width * scale > maxW )
			scale = maxW / tex.Width;
		if ( tex.Height * scale > maxH )
			scale = MathF.Min( scale, maxH / tex.Height );

		scale = Math.Clamp( scale, floor, prefer );
		// Snap to half-pixels for stable alignment
		scale = MathF.Round( scale * 2f ) / 2f;
		if ( scale < floor )
			scale = floor;

		// Integer panel size — avoids subpixel drift / misalignment in S&box UI
		var w = MathF.Max( 1f, MathF.Round( tex.Width * scale ) );
		var h = MathF.Max( 1f, MathF.Round( tex.Height * scale ) );

		Style.Width = Length.Pixels( w );
		Style.Height = Length.Pixels( h );
		Style.BackgroundImage = tex;
		try
		{
			Style.BackgroundSizeX = Length.Pixels( w );
			Style.BackgroundSizeY = Length.Pixels( h );
		}
		catch
		{
			// optional style props
		}

		_appliedKey = key;
	}
}