Show ° and % inside the Select Color number boxes

Draw the unit as the NumberInput icon on the right of the digits
instead of a separate label beside the box. The unit is not part of the
value, so users still only type the number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013rGmDUNr1hUf4zo1X3dak8
This commit is contained in:
Claude committed 2026-10-11 20:55:38 +00:00
1 parent 43f88732ea
commit 3d7db54c23
1 file changed
+38 -40
+38 -40
View File
@@ -552,28 +552,25 @@ impl ColorPicker {
v * 360.0 v * 360.0
))) )))
.wheel_step(1.0 / 360.0), .wheel_step(1.0 / 360.0),
number_box(h.round() as u16, 360, |v| { number_box(h.round() as u16, 360, Some('°'), |v| {
picker_msg(ColorPickerMsg::Hue(f32::from(v))) picker_msg(ColorPickerMsg::Hue(f32::from(v)))
}), }),
"°",
), ),
slider_row( slider_row(
"S", "S",
GradientSlider::new(s, sat_stops, |v| picker_msg(ColorPickerMsg::Saturation(v))), GradientSlider::new(s, sat_stops, |v| picker_msg(ColorPickerMsg::Saturation(v))),
number_box((s * 100.0).round() as u16, 100, |v| { number_box((s * 100.0).round() as u16, 100, Some('%'), |v| {
picker_msg(ColorPickerMsg::Saturation(f32::from(v) / 100.0)) picker_msg(ColorPickerMsg::Saturation(f32::from(v) / 100.0))
}), }),
"%",
), ),
slider_row( slider_row(
"B", "B",
GradientSlider::new(b, bright_stops, |v| picker_msg(ColorPickerMsg::Brightness( GradientSlider::new(b, bright_stops, |v| picker_msg(ColorPickerMsg::Brightness(
v v
))), ))),
number_box((b * 100.0).round() as u16, 100, |v| { number_box((b * 100.0).round() as u16, 100, Some('%'), |v| {
picker_msg(ColorPickerMsg::Brightness(f32::from(v) / 100.0)) picker_msg(ColorPickerMsg::Brightness(f32::from(v) / 100.0))
}), }),
"%",
), ),
] ]
.spacing(10) .spacing(10)
@@ -597,10 +594,9 @@ impl ColorPicker {
picker_msg(ColorPickerMsg::Red(byte(v))) picker_msg(ColorPickerMsg::Red(byte(v)))
}) })
.wheel_step(1.0 / 255.0), .wheel_step(1.0 / 255.0),
number_box(u16::from(r), 255, |v| picker_msg(ColorPickerMsg::Red( number_box(u16::from(r), 255, None, |v| picker_msg(
v as u8 ColorPickerMsg::Red(v as u8)
))), )),
"",
), ),
slider_row( slider_row(
"G", "G",
@@ -608,10 +604,9 @@ impl ColorPicker {
picker_msg(ColorPickerMsg::Green(byte(v))) picker_msg(ColorPickerMsg::Green(byte(v)))
}) })
.wheel_step(1.0 / 255.0), .wheel_step(1.0 / 255.0),
number_box(u16::from(g), 255, |v| picker_msg(ColorPickerMsg::Green( number_box(u16::from(g), 255, None, |v| picker_msg(
v as u8 ColorPickerMsg::Green(v as u8)
))), )),
"",
), ),
slider_row( slider_row(
"B", "B",
@@ -619,10 +614,9 @@ impl ColorPicker {
picker_msg(ColorPickerMsg::Blue(byte(v))) picker_msg(ColorPickerMsg::Blue(byte(v)))
}) })
.wheel_step(1.0 / 255.0), .wheel_step(1.0 / 255.0),
number_box(u16::from(b), 255, |v| picker_msg(ColorPickerMsg::Blue( number_box(u16::from(b), 255, None, |v| picker_msg(
v as u8 ColorPickerMsg::Blue(v as u8)
))), )),
"",
), ),
] ]
.spacing(10) .spacing(10)
@@ -643,38 +637,31 @@ impl ColorPicker {
.height(Length::Fixed(118.0)) .height(Length::Fixed(118.0))
.wheel_step(1.0 / 360.0); .wheel_step(1.0 / 360.0);
let field = |letter: &'static str, input: Element<'static, Message>, unit: &'static str| { let field = |letter: &'static str, input: Element<'static, Message>| {
row![ row![text(letter).size(12).font(iced::Font::MONOSPACE), input]
text(letter).size(12).font(iced::Font::MONOSPACE), .spacing(4)
input, .align_y(iced::Center)
text(unit).size(11).style(muted_text),
]
.spacing(4)
.align_y(iced::Center)
}; };
let values = row![ let values = row![
field( field(
"H", "H",
number_box(h.round() as u16, 360, |v| picker_msg(ColorPickerMsg::Hue( number_box(h.round() as u16, 360, Some('°'), |v| picker_msg(
f32::from(v) ColorPickerMsg::Hue(f32::from(v))
))), )),
"°",
), ),
Space::new().width(Length::Fill), Space::new().width(Length::Fill),
field( field(
"S", "S",
number_box((s * 100.0).round() as u16, 100, |v| { number_box((s * 100.0).round() as u16, 100, Some('%'), |v| {
picker_msg(ColorPickerMsg::Saturation(f32::from(v) / 100.0)) picker_msg(ColorPickerMsg::Saturation(f32::from(v) / 100.0))
}), }),
"%",
), ),
Space::new().width(Length::Fill), Space::new().width(Length::Fill),
field( field(
"B", "B",
number_box((b * 100.0).round() as u16, 100, |v| { number_box((b * 100.0).round() as u16, 100, Some('%'), |v| {
picker_msg(ColorPickerMsg::Brightness(f32::from(v) / 100.0)) picker_msg(ColorPickerMsg::Brightness(f32::from(v) / 100.0))
}), }),
"%",
), ),
] ]
.align_y(iced::Center); .align_y(iced::Center);
@@ -781,7 +768,6 @@ fn slider_row<'a>(
letter: &'static str, letter: &'static str,
slider: GradientSlider<'a, Message>, slider: GradientSlider<'a, Message>,
number: Element<'a, Message>, number: Element<'a, Message>,
unit: &'static str,
) -> Element<'a, Message> { ) -> Element<'a, Message> {
row![ row![
container(text(letter).size(12).font(iced::Font::MONOSPACE)) container(text(letter).size(12).font(iced::Font::MONOSPACE))
@@ -789,7 +775,6 @@ fn slider_row<'a>(
.align_x(iced::Center), .align_x(iced::Center),
slider, slider,
number, number,
container(text(unit).size(11).style(muted_text)).width(10),
] ]
.spacing(8) .spacing(8)
.align_y(iced::Center) .align_y(iced::Center)
@@ -801,12 +786,13 @@ fn slider_row<'a>(
fn number_box( fn number_box(
value: u16, value: u16,
max: u16, max: u16,
unit: Option<char>,
on_change: impl Fn(u16) -> Message + Clone + 'static, on_change: impl Fn(u16) -> Message + Clone + 'static,
) -> Element<'static, Message> { ) -> Element<'static, Message> {
iced_aw::widget::NumberInput::new(&value, 0..=max, on_change) let input = iced_aw::widget::NumberInput::new(&value, 0..=max, on_change)
.set_size(12.0) .set_size(12.0)
.font(iced::Font::MONOSPACE) .font(iced::Font::MONOSPACE)
.width(Length::Fixed(64.0)) .width(Length::Fixed(68.0))
// Extra right padding keeps the digits clear of the arrows; padding // Extra right padding keeps the digits clear of the arrows; padding
// below 5 would make NumberInput swap its arrows for + / − buttons. // below 5 would make NumberInput swap its arrows for + / − buttons.
.padding(iced::Padding { .padding(iced::Padding {
@@ -821,8 +807,20 @@ fn number_box(
button_background: None, button_background: None,
icon_color: theme.palette().background.base.text.scale_alpha(0.75), icon_color: theme.palette().background.base.text.scale_alpha(0.75),
}, },
) );
.into() // The unit is drawn inside the box, after the digits, but is not part
// of the value: the user only ever types the number.
let input = match unit {
Some(code_point) => input.icon(text_input::Icon {
font: iced::Font::MONOSPACE,
code_point,
size: Some(iced::Pixels(12.0)),
spacing: 1.0,
side: text_input::Side::Right,
}),
None => input,
};
input.into()
} }
fn hue_stops() -> Vec<(f32, Color)> { fn hue_stops() -> Vec<(f32, Color)> {