LightTemperature.cs
using Sandbox;

namespace RotSoft.Lighting;




/// <summary>
/// Adjusts the <see cref="Color"/> of a <see cref="Light"/> component using Color <see cref="Temperature"/> in Kelvin.
/// Applies once on add and whenever the temperature or brightness changes, so the light's color stays manually editable.
/// </summary>
[Title( "Light Temperature" )]
[Category( "Light" )]
[Icon( "thermostat" )]
[Alias( "Temperature", "Kelvin" )]
public sealed class LightTemperature : Component, Component.ExecuteInEditor
{
	/// <summary>Common light temperature presets in Kelvin.</summary>
	public enum LightTemperaturePreset
	{
		/// <summary>1000 K</summary>
		MatchFlame = 1700,
		/// <summary>2400 K</summary>
		Incandescent = 2400,
		/// <summary>2700 K</summary>
		WarmWhite = 3000,
		/// <summary>3200 K</summary>
		Studio = 3200,
		/// <summary>5000 K</summary>
		CoolWhite = 5000,
		/// <summary>6500 K</summary>
		Daylight = 6500,
		/// <summary>6500 K</summary>
		LCD = 9500,
		/// <summary>7500 K</summary>
		BlueSky = 15000,
		/// <summary>Custom value, set it with the Kelvin slider.</summary>
		Custom = 0,
	}

	LightTemperaturePreset _preset = LightTemperaturePreset.CoolWhite;
	float _kelvin = 5000f;
	float _brightness = 1f;
	bool _syncing;
	Light _light;

	/// <summary>Standard light temperature presets.</summary>
	[Property]
	public LightTemperaturePreset Preset
	{
		get => _preset;
		set
		{
			if ( _preset == value ) return;
			_preset = value;
			if ( value != LightTemperaturePreset.Custom )
			{
				_syncing = true;
				Kelvin = (float)(int)value;
				_syncing = false;
			}
			else
			{
				ApplyColor();
			}
		}
	}

	/// <summary>The color temperature in Kelvin.</summary>
	[Property, Title( "Temperature (K)" ), Range( 1500, 15000 ), KelvinSlider]
	public float Kelvin
	{
		get => _kelvin;
		set
		{
			if ( _kelvin == value ) return;
			_kelvin = value;
			if ( !_syncing && _preset != LightTemperaturePreset.Custom )
				_preset = LightTemperaturePreset.Custom;
			ApplyColor();
		}
	}

	/// <summary>The brightness (range) of the Light.</summary>
	[Property, Range( 0, 5f ), Step( 0.01f )]
	public float Brightness
	{
		get => _brightness;
		set
		{
			if ( _brightness == value ) return;
			_brightness = value;
			ApplyColor();
		}
	}

	/// <summary>Applies the current temperature and brightness to the <see cref="Light"/>'s color once on add.</summary>
	protected override void OnStart()
	{
		ApplyColor();
	}

	/// <summary>Sets the <see cref="Light"/>'s color from the current temperature and brightness, if a light is present.</summary>
	void ApplyColor()
	{
		_light ??= GetComponentInChildren<Light>( true );
		if ( _light is null ) return;
		_light.LightColor = new Temperature( Kelvin ).ToColor() * Brightness;
	}
}