Color Ring
Edit a color channel on a full circular track.
Try it
Drag around the hue ring, or use arrow keys, to update the preview and committed hue. This preview runs the exact code sample below.
Basic use
use gpui::{Context, Entity, Render, Window, div, prelude::*, px};
use xgpui_luma::controls::slider::{SliderControl, SliderEventExt};
use xgpui_luma_color::color_ring::ColorRingBuilder;
use xgpui_luma_color::style::Size;
struct Example {
control: Entity<SliderControl>,
preview: f32,
committed: f32,
}
impl Example {
fn new(cx: &mut Context<Self>) -> Self {
let control = ColorRingBuilder::hue("hue-ring", 210.0, 0.8, 0.5)
.size(Size::Medium).allow_inner_target(true)
.keyboard_step_degrees(1.0)
.spawn(cx)
.on_value_changed(cx, |owner: &mut Self, _, value, cx| {
owner.preview = value;
cx.notify();
})
.on_release(cx, |owner, _, value, cx| {
owner.committed = value;
cx.notify();
});
Self { control, preview: 210.0, committed: 210.0 }
}
}
impl Render for Example {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div().w(px(240.0)).child(self.control.clone())
}
}Channels and appearance
hue(id, hue, saturation, lightness) builds a hue ring. saturation(id, saturation, hue, hsv_value) and lightness(id, lightness, hue, saturation) build the other channel tracks; their scalar values use 0..1.
Use size(Size), ring_thickness, thumb_size, rotation_degrees, and inner/outer border options. allow_inner_target(true) also accepts interaction inside the ring; leave it false when another control occupies the center. Raster rendering is the default; hue_with_renderer and the equivalent channel constructors accept ColorRingRenderer.
Events
| Event | Payload | Callback |
|---|---|---|
Change | thumb_id: ThumbIdvalue: f32 | on_value_changedUpdate the live preview. |
Release | thumb_id: ThumbIdvalue: f32 | on_releaseCommit the interaction value. |
DragStart | thumb_id: ThumbId | on_drag_startBegin a pointer gesture. |
DragEnd | thumb_id: ThumbIdvalue: f32 | on_drag_endFinish a pointer gesture. |
ThumbAdded | thumb_id: ThumbIdvalue: f32 | on_thumb_addedTrack an added gradient stop. |
ThumbRemoved | thumb_id: ThumbId | on_thumb_removedTrack a removed stop. |
ThumbSelected | thumb_id: ThumbId | on_thumb_selectedUpdate the selected thumb. |
FocusChanged | focused: bool | on_focus_changedReact to keyboard focus. |
HoverChanged | hovered: bool | on_hover_changedReact to pointer hover. |
EnabledChanged | enabled: bool | on_enabled_changedReact to enablement changes. |
These are SDK SliderEvent callbacks, available through SliderEventExt. The builders return Entity<SliderControl>. Each callback receives the owner, the listed payload values, and the owner context. Register callbacks after spawn; use on_event or cx.subscribe for the full event stream. See Slider events.
Keyboard and synchronization
Arrow keys move by 1 degree around the track, or 10 with Shift. keyboard_step_degrees changes the angular increment; step separately controls scalar snapping. Navigation wraps at the angular seam and preserves the current side of mirrored saturation/lightness tracks.
Retain domain_renderer() and track_context() before spawning. Update dependent color delegates and refresh thumb previews with update_ring_delegate / refresh_color_ring, or use the corresponding ColorCompositionSync helper. Numeric value changes alone do not update the base colors of the track.