Skip to content

Instantly share code, notes, and snippets.

@andrew-raphael-lukasik
Last active February 10, 2026 09:32
Show Gist options
  • Select an option

  • Save andrew-raphael-lukasik/e7476208779f70e66fbedf5eb10aa2f8 to your computer and use it in GitHub Desktop.

Select an option

Save andrew-raphael-lukasik/e7476208779f70e66fbedf5eb10aa2f8 to your computer and use it in GitHub Desktop.
basic color picker for UI Toolkit

Color picker / UI Toolkit

GIF 08 11 2023 01-37-22

// src*: https://gist.github.com/andrew-raphael-lukasik/e7476208779f70e66fbedf5eb10aa2f8
using UnityEngine;
using UnityEngine.UIElements;
[UnityEngine.Scripting.Preserve]
public class ColorPickerElement : VisualElement
{
public new class UxmlFactory : UxmlFactory<ColorPickerElement,UxmlTraits> {}
public new class UxmlTraits : VisualElement.UxmlTraits
{
UxmlFloatAttributeDescription hueAttr = new UxmlFloatAttributeDescription{ name="hue" , defaultValue=0.5f };
UxmlFloatAttributeDescription brightnessAttr = new UxmlFloatAttributeDescription{ name="brightness" , defaultValue=1f };
public override void Init ( VisualElement ve , IUxmlAttributes attributes , CreationContext context )
{
base.Init( ve , attributes , context );
var instance = (ColorPickerElement) ve;
instance.hue = hueAttr.GetValueFromBag(attributes,context);
instance.brightness = brightnessAttr.GetValueFromBag(attributes,context);
}
}
public float hue { get; set; }
public float brightness { get; set; }
public Color color => Color.HSVToRGB(1-hue%1,1,brightness);
public Gradient circleGradient { get; set; } = new Gradient{
mode = GradientMode.Blend ,
colorKeys = new GradientColorKey[]{
new GradientColorKey( Color.HSVToRGB(0,1,1) , 0 ) ,
new GradientColorKey( Color.HSVToRGB(1*1f/6f,1,1) , 1*1f/6f ) ,
new GradientColorKey( Color.HSVToRGB(2*1f/6f,1,1) , 2*1f/6f ) ,
new GradientColorKey( Color.HSVToRGB(3*1f/6f,1,1) , 3*1f/6f ) ,
new GradientColorKey( Color.HSVToRGB(4*1f/6f,1,1) , 4*1f/6f ) ,
new GradientColorKey( Color.HSVToRGB(5*1f/6f,1,1) , 5*1f/6f ) ,
new GradientColorKey( Color.HSVToRGB(1,1,1) , 1 ) ,
}
};
public ColorPickerElement ()
{
generateVisualContent += OnGenerateVisualContent;
this.RegisterCallback<ClickEvent>( OnMouseClicked );
}
void OnMouseClicked ( ClickEvent evt )
{
Vector2 dir = (Vector2)evt.localPosition - contentRect.center;
hue = 0.25f + ( Mathf.Atan2(-dir.y,dir.x) / Mathf.PI ) * -0.5f;
Rect rect = contentRect;
float swh = Mathf.Min( rect.width , rect.height );// smaller dimension
brightness = dir.magnitude / (swh*0.4f);
this.MarkDirtyRepaint();
}
void OnGenerateVisualContent ( MeshGenerationContext mgc )
{
Rect rect = contentRect;
float swh = Mathf.Min( rect.width , rect.height );// smaller dimension
if( swh<0.01f ) return;// skip rendering when collapsed
var paint = mgc.painter2D;
float circleRadius = swh*0.4f;
float gradientWidth = swh*0.05f;
// selected color circle
paint.BeginPath();
{
paint.Arc( rect.center , circleRadius-gradientWidth/2 , 0 , 360 );
paint.fillColor = color;
paint.Fill();
}
paint.ClosePath();
// color ring
paint.BeginPath();
{
paint.Arc( rect.center , circleRadius , 270-0.001f , -90 , ArcDirection.CounterClockwise );
paint.lineWidth = gradientWidth + 0.2f;
paint.strokeColor = Color.black;
paint.Stroke();// border
paint.lineWidth = gradientWidth;
paint.strokeGradient = circleGradient;
paint.Stroke();// hues
}
paint.ClosePath();
// hue position marker
paint.BeginPath();
{
float hueAngle = -Mathf.PI/2 + hue * Mathf.PI*2;
paint.Arc( rect.center + Vector2.Scale(new Vector2(circleRadius,circleRadius),new Vector2(Mathf.Cos(hueAngle),Mathf.Sin(hueAngle))) , swh*0.03f , 0 , 360 );
paint.lineWidth = 0.4f;
paint.strokeColor = Color.white;
paint.Stroke();
}
paint.ClosePath();
}
}
@Swahhillie
Copy link

I put this picker in a draggable window. For that to work I needed to add evt.StopImmediatePropagation(); to all the callback registrations. Otherwise dragging on the color picker would drag the parent window.

Great component!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment