ColorPicker¶
Header: winui/ui/input/ColorPicker.hpp. Spec: winui/ui/input/ColorPicker.hpp.
A hue/saturation/value/alpha color editor with channel, alpha and hex text entry and a preview swatch.
A container of independently focusable sub-controls, laid out vertically from the top: hue and saturation sliders beside the preview (standing in for the 2D spectrum, which is not drawn), the value slider, the alpha slider, an optional More button, then the text entry section (an RGB/HSV dropdown and a #RRGGBB hex box, three channel boxes and an Opacity box). Tab walks the parts in that order; the picker itself is never focused.
Every part has a *_visible switch. A hidden part is not laid out, drawn, hit-tested or reachable by Tab, and showing it again needs no rebuild. A channel box applies a valid value as it is typed (0-255 for RGB, 0-359 hue, 0-100 saturation, value and opacity); Enter reverts invalid text. The hex box commits on Enter only: 6 or 8 hex digits (#RRGGBBAA, '#' optional, case-insensitive); anything else reverts.
Example:
auto row = std::make_unique<ui::StackControl>(ui::Orientation::Horizontal);
ui::ColorPickerControl* picker = row->add(std::make_unique<ui::ColorPickerControl>(ui::Color::from_rgba(0, 120, 215),
/*alpha_enabled=*/true));
picker->set_more_button_visible(true); // text entry collapsed behind "More"
ui::BorderControl* swatch = row->add(std::make_unique<ui::BorderControl>());
swatch->set_width(100.0f);
swatch->set_height(100.0f);
swatch->set_background(picker->color());
picker->on_color_changed([swatch](ui::Color c) { swatch->set_background(c); });
window.set_content(std::move(row));
// Declaratively, two-way through a Property (the equality gate stops the echo):
ui::Property<ui::Color> accent{ui::Color::from_rgba(0, 120, 215)};
window.set_content(ui::HorizontalStack{
.spacing = 16,
.content = {
ui::ColorPicker{
.color = accent,
.alpha_enabled = true,
.more_button_visible = true,
},
ui::Border{.background = ui::bind(accent, [](ui::Color c) { return std::optional{c}; }),
.width = 100.0f,
.height = 100.0f},
},
});
ui::ColorPicker¶
A hue/saturation/value/alpha color editor with channel, alpha and hex text entry and a preview swatch. Builds a ui::ColorPickerControl. Each *_visible field shows or hides one part; ui::ColorPickerControl's class comment describes the parts.
.color = prop is two-way: it shows the property and writes the picked color back into it before on_color_changed runs.
Example:
ui::Property<ui::Color> accent{ui::Color::from_rgba(0, 120, 215)};
window.set_content(ui::HorizontalStack{.spacing = 16, .content = {
ui::ColorPicker{
.color = accent,
.alpha_enabled = true,
.more_button_visible = true,
.horizontal_alignment = ui::Alignment::Leading,
},
ui::Border{.background = ui::bind(accent, [](ui::Color c) { return std::optional{c}; }),
.width = 100.0f,
.height = 100.0f},
}});
Every field, in the order a designated initializer names them:
ui::ColorPicker{
.color, .alpha_enabled, .spectrum_visible, .preview_visible, .color_slider_visible,
.alpha_slider_visible, .more_button_visible, .color_channel_text_input_visible,
.alpha_text_input_visible, .hex_input_visible, .style, .margin, .width, .height,
.min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
.vertical_alignment, .visible, .tool_tip, .enabled, .accessibility, .on_color_changed,
.on_pointer_entered, .on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down,
.on_wheel, .control
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
color |
ui::TwoWayField<ui::Color> |
{ui::colors::Black} |
The selected color. Its alpha is kept only while alpha_enabled is true. |
alpha_enabled |
ui::Binding<bool> |
{false} |
Show and honor the alpha channel. Applied before color. |
spectrum_visible |
ui::Binding<bool> |
{true} |
The hue and saturation sliders. |
preview_visible |
ui::Binding<bool> |
{true} |
The preview swatch. |
color_slider_visible |
ui::Binding<bool> |
{true} |
The value slider. |
alpha_slider_visible |
ui::Binding<bool> |
{true} |
The alpha slider (with alpha_enabled). |
more_button_visible |
ui::Binding<bool> |
{false} |
The More button. |
color_channel_text_input_visible |
ui::Binding<bool> |
{true} |
The RGB/HSV dropdown and channel boxes. |
alpha_text_input_visible |
ui::Binding<bool> |
{true} |
The Opacity box (with alpha_enabled). |
hex_input_visible |
ui::Binding<bool> |
{true} |
The #RRGGBB box. |
on_color_changed |
ui::Callback<void(ui::Color)> |
Fires with the new color when it changes, from any part (slider drag, keyboard step, typed channel value or committed hex edit). | |
on_pointer_entered |
ui::Action |
The pointer moved onto the control. | |
on_pointer_exited |
ui::Action |
The pointer left the control. | |
on_got_focus |
ui::Action |
Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this. | |
on_lost_focus |
ui::Action |
Keyboard focus left the control and everything inside it. | |
on_key_down |
ui::Callback<ui::Handling(const ui::KeyEvent&)> |
A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()). | |
on_wheel |
ui::Callback<ui::Handling(const ui::PointerEvent&)> |
A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()). | |
control |
ui::ControlOut<ui::ColorPicker> |
Out: the handle that receives the built control. |
Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, enabled, accessibility every spec carries (conventions).
build¶
Consumes the spec and returns the built ui::ColorPickerControl; the caller owns it.
ui::ColorPickerControl¶
Derives from ui::Element.
A hue/saturation/value/alpha color editor with channel, alpha and hex text entry and a preview swatch.
A container of independently focusable sub-controls, laid out vertically from the top: hue and saturation sliders beside the preview (standing in for the 2D spectrum, which is not drawn), the value slider, the alpha slider, an optional More button, then the text entry section (an RGB/HSV dropdown and a #RRGGBB hex box, three channel boxes and an Opacity box). Tab walks the parts in that order; the picker itself is never focused.
Every part has a *_visible switch. A hidden part is not laid out, drawn, hit-tested or reachable by Tab, and showing it again needs no rebuild. A channel box applies a valid value as it is typed (0-255 for RGB, 0-359 hue, 0-100 saturation, value and opacity); Enter reverts invalid text. The hex box commits on Enter only: 6 or 8 hex digits (#RRGGBBAA, '#' optional, case-insensitive); anything else reverts.
Example:
auto row = std::make_unique<ui::StackControl>(ui::Orientation::Horizontal);
ui::ColorPickerControl* picker = row->add(std::make_unique<ui::ColorPickerControl>(ui::Color::from_rgba(0, 120, 215),
/*alpha_enabled=*/true));
picker->set_more_button_visible(true); // text entry collapsed behind "More"
ui::BorderControl* swatch = row->add(std::make_unique<ui::BorderControl>());
swatch->set_width(100.0f);
swatch->set_height(100.0f);
swatch->set_background(picker->color());
picker->on_color_changed([swatch](ui::Color c) { swatch->set_background(c); });
window.set_content(std::move(row));
// Declaratively, two-way through a Property (the equality gate stops the echo):
ui::Property<ui::Color> accent{ui::Color::from_rgba(0, 120, 215)};
window.set_content(ui::HorizontalStack{
.spacing = 16,
.content = {
ui::ColorPicker{
.color = accent,
.alpha_enabled = true,
.more_button_visible = true,
},
ui::Border{.background = ui::bind(accent, [](ui::Color c) { return std::optional{c}; }),
.width = 100.0f,
.height = 100.0f},
},
});
ColorPickerControl¶
A picker showing color; its alpha is kept only when alpha_enabled.
~ColorPickerControl¶
Destroys the owned sub-controls.
color¶
The selected color, computed from the sliders' HSV values on every call. Opaque while alpha_enabled() is false.
set_color¶
Forces alpha to 1 when alpha_enabled() is false; updates every slider, box and the preview. Fires on_color_changed only if the resulting color differs from the current one.
alpha_enabled¶
Whether the alpha channel is shown and honored; false by default. While false, the alpha slider and box are hidden regardless of their own switches and the color is opaque.
set_alpha_enabled¶
Turns the alpha channel on or off. Turning it off makes the color opaque, firing on_color_changed if that changes it.
spectrum_visible¶
Whether the hue and saturation sliders show; true by default.
set_spectrum_visible¶
Shows or hides the hue and saturation sliders standing in for the spectrum. Hiding them stretches the preview across the row at 44 DIPs tall. Updates the layout.
preview_visible¶
Whether the preview swatch shows; true by default.
set_preview_visible¶
Shows or hides the swatch showing the current color. Updates the layout.
color_slider_visible¶
Whether the value slider shows; true by default.
set_color_slider_visible¶
Shows or hides the value slider. Updates the layout.
alpha_slider_visible¶
Whether the alpha slider shows; true by default, but shown only while alpha_enabled() too.
set_alpha_slider_visible¶
Shows or hides the alpha slider, shown only while alpha_enabled() too. Updates the layout.
more_button_visible¶
Whether the More button shows; false by default.
set_more_button_visible¶
Shows or hides the More button. While shown, the text entry section is collapsed until the button is clicked. Updates the layout.
color_channel_text_input_visible¶
Whether the channel inputs show; true by default.
set_color_channel_text_input_visible¶
Shows or hides the RGB/HSV dropdown and the three channel boxes. Hiding them moves the hex box to the left. Updates the layout.
alpha_text_input_visible¶
Whether the Opacity box shows; true by default, but shown only while alpha_enabled() too.
set_alpha_text_input_visible¶
Shows or hides the Opacity box, shown only while alpha_enabled() too. Updates the layout.
hex_input_visible¶
Whether the #RRGGBB box shows; true by default.
set_hex_input_visible¶
Shows or hides the #RRGGBB box. Updates the layout.
more_expanded¶
Whether the text entry section is expanded behind the More button. Meaningless while the button is hidden, when the section is always shown.
on_color_changed¶
Fired with the new color whenever color changes, from a slider drag, a click-to-jump on any channel's track, a keyboard step, a typed channel value, a committed hex edit or set_color() alike. Replaces any previous handler.
for_each_child¶
Lists the shown sub-controls in Tab order, so a hidden part gets no focus, input, animation or automation. The picker itself is never a tab stop.
measure_override¶
Stacks the shown parts at the available width; the height follows from what is shown.
arrange_override¶
Places every shown part.
render_override¶
Draws the shown sub-controls, the channel labels and the preview swatch.
clear_dirty_override¶
Reaches every sub-control, shown or not, unlike for_each_child(), so a part that comes back into view does not carry flags from before it was hidden.
enabled_changed¶
is_enabled() flipped, through set_enabled() here or on an ancestor, or a move to another parent. Drop any press or hover state. The element is redrawn either way. No-op by default.
Tests¶
tests/test_color_picker.cpp