veloren_voxygen/ui/widgets/
radio_list.rs1use conrod_core::{
2 Color, FontSize, Positionable, Rect, Sizeable, Widget, WidgetCommon, builder_methods, image,
3 text,
4 widget::{self, button},
5 widget_ids,
6};
7
8#[derive(Clone, WidgetCommon)]
9pub struct RadioList<'a, T> {
10 #[conrod(common_builder)]
11 common: widget::CommonBuilder,
12 f_image: button::Image,
13 t_image: button::Image,
14 selected: usize,
15 options_labels: &'a [(&'a T, &'a str)],
16 label_style: widget::text::Style,
17 label_spacing: f64,
18 button_spacing: [f64; 2],
19 button_dims: [f64; 2],
20}
21
22widget_ids! {
23 struct Ids {
24 buttons[],
25 labels[],
26 }
27}
28
29pub struct State {
30 ids: Ids,
31}
32
33impl<'a, T> RadioList<'a, T> {
34 builder_methods! {
35 pub text_color { label_style.color = Some(Color) }
36 pub font_size { label_style.font_size = Some(FontSize) }
37 pub justify { label_style.justify = Some(text::Justify) }
38 pub line_spacing { label_style.line_spacing = Some(f64) }
39 pub label_spacing { label_spacing = f64 }
40 pub button_spacing { button_spacing = [f64; 2] }
41 pub button_dims { button_dims = [f64; 2] }
42 }
43
44 pub fn new(
45 selected: usize,
46 f_image_id: image::Id,
47 t_image_id: image::Id,
48 options_labels: &'a [(&'a T, &'a str)],
49 ) -> Self {
50 Self {
51 common: widget::CommonBuilder::default(),
52 f_image: button::Image {
53 image_id: f_image_id,
54 hover_image_id: None,
55 press_image_id: None,
56 src_rect: None,
57 color: button::ImageColor::None,
58 },
59 t_image: button::Image {
60 image_id: t_image_id,
61 hover_image_id: None,
62 press_image_id: None,
63 src_rect: None,
64 color: button::ImageColor::None,
65 },
66 selected,
67 label_style: widget::text::Style::default(),
68 options_labels,
69 label_spacing: 10.0,
70 button_spacing: [5.0, 5.0],
71 button_dims: [15.0, 15.0],
72 }
73 }
74
75 #[must_use]
76 pub fn source_rectangle(mut self, rect: Rect) -> Self {
77 self.f_image.src_rect = Some(rect);
78 self.t_image.src_rect = Some(rect);
79 self
80 }
81
82 #[must_use]
83 pub fn image_colors(mut self, f_color: Color, t_color: Color) -> Self {
84 self.f_image.color = button::ImageColor::Normal(f_color);
85 self.t_image.color = button::ImageColor::Normal(t_color);
86 self
87 }
88
89 #[must_use]
90 pub fn image_color_with_feedback(mut self, f_color: Color, t_color: Color) -> Self {
91 self.f_image.color = button::ImageColor::WithFeedback(f_color);
92 self.t_image.color = button::ImageColor::WithFeedback(t_color);
93 self
94 }
95
96 #[must_use]
97 pub fn hover_images(mut self, f_id: image::Id, t_id: image::Id) -> Self {
98 self.f_image.hover_image_id = Some(f_id);
99 self.t_image.hover_image_id = Some(t_id);
100 self
101 }
102
103 #[must_use]
104 pub fn press_images(mut self, f_id: image::Id, t_id: image::Id) -> Self {
105 self.f_image.press_image_id = Some(f_id);
106 self.t_image.press_image_id = Some(t_id);
107 self
108 }
109}
110
111impl<'a, T> Widget for RadioList<'a, T> {
112 type Event = Option<(usize, &'a T)>;
113 type State = State;
114 type Style = ();
115
116 fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
117 State {
118 ids: Ids::new(id_gen),
119 }
120 }
121
122 fn style(&self) -> Self::Style {}
123
124 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
125 let widget::UpdateArgs {
126 id,
127 state,
128 ui,
129 rect,
130 ..
131 } = args;
132 let Self {
133 f_image,
134 t_image,
135 selected,
136 options_labels,
137 label_style,
138 label_spacing,
139 button_spacing,
140 button_dims,
141 ..
142 } = self;
143
144 let num_items = options_labels.len();
146 if state.ids.buttons.len() < num_items || state.ids.labels.len() < num_items {
147 state.update(|s| {
148 s.ids
149 .buttons
150 .resize(num_items, &mut ui.widget_id_generator());
151 s.ids
152 .labels
153 .resize(num_items, &mut ui.widget_id_generator());
154 });
155 }
156
157 let current_selection = (0..num_items)
162 .find(|i| {
163 ui.widget_input(state.ids.buttons[*i])
164 .clicks()
165 .left()
166 .count()
167 % 2
168 == 1
169 })
170 .unwrap_or(selected);
171
172 let (x, y, w, h) = rect.x_y_w_h();
173 for (i, _j) in options_labels.iter().enumerate().take(num_items) {
174 let image = if i == current_selection {
175 t_image
176 } else {
177 f_image
178 };
179 let mut button = button::Button::image(image.image_id)
181 .wh(button_dims)
182 .x_y(
184 x - w / 2.0 + button_spacing[0],
185 y - h / 2.0
186 - i as f64 * (button_dims[1] + button_spacing[1])
187 - button_spacing[1],
188 )
189 .parent(id);
190 button.show = image;
191 button.set(state.ids.buttons[i], ui);
192 widget::Text::new(options_labels[i].1)
194 .graphics_for(state.ids.buttons[i])
195 .parent(id)
196 .with_style(label_style)
197 .right_from(state.ids.buttons[i], label_spacing)
198 .set(state.ids.labels[i], ui);
199 }
200
201 if current_selection != selected {
202 Some((current_selection, options_labels[current_selection].0))
203 } else {
204 None
205 }
206 }
207}