egui/widgets/
radio_button.rs1use crate::{
2 Atom, AtomLayout, Atoms, Id, IntoAtoms, NumExt as _, Response, Sense, Ui, Vec2, Widget,
3 WidgetInfo, WidgetType, epaint,
4};
5
6#[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
26pub struct RadioButton<'a> {
27 checked: bool,
28 atoms: Atoms<'a>,
29}
30
31impl<'a> RadioButton<'a> {
32 pub fn new(checked: bool, atoms: impl IntoAtoms<'a>) -> Self {
33 Self {
34 checked,
35 atoms: atoms.into_atoms(),
36 }
37 }
38}
39
40impl Widget for RadioButton<'_> {
41 fn ui(self, ui: &mut Ui) -> Response {
42 let Self { checked, mut atoms } = self;
43
44 let spacing = &ui.spacing();
45 let icon_width = spacing.icon_width;
46
47 let mut min_size = Vec2::splat(spacing.interact_size.y);
48 min_size.y = min_size.y.at_least(icon_width);
49
50 let mut icon_size = Vec2::splat(icon_width);
52 icon_size.y = icon_size.y.at_least(min_size.y);
53 let rect_id = Id::new("egui::radio_button");
54 atoms.push_left(Atom::custom(rect_id, icon_size));
55
56 let text = atoms.text().map(String::from);
57
58 let mut prepared = AtomLayout::new(atoms)
59 .sense(Sense::click())
60 .min_size(min_size)
61 .allocate(ui);
62
63 prepared.response.widget_info(|| {
64 WidgetInfo::selected(
65 WidgetType::RadioButton,
66 ui.is_enabled(),
67 checked,
68 text.as_deref().unwrap_or(""),
69 )
70 });
71
72 if ui.is_rect_visible(prepared.response.rect) {
73 let visuals = *ui.style().interact(&prepared.response);
75
76 prepared.fallback_text_color = visuals.text_color();
77 let response = prepared.paint(ui);
78
79 if let Some(rect) = response.rect(rect_id) {
80 let (small_icon_rect, big_icon_rect) = ui.spacing().icon_rectangles(rect);
81
82 let painter = ui.painter();
83
84 painter.add(epaint::CircleShape {
85 center: big_icon_rect.center(),
86 radius: big_icon_rect.width() / 2.0 + visuals.expansion,
87 fill: visuals.bg_fill,
88 stroke: visuals.bg_stroke,
89 });
90
91 if checked {
92 painter.add(epaint::CircleShape {
93 center: small_icon_rect.center(),
94 radius: small_icon_rect.width() / 3.0,
95 fill: visuals.fg_stroke.color, stroke: Default::default(),
98 });
99 }
100 }
101 response.response
102 } else {
103 prepared.response
104 }
105 }
106}