1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::Event;
use crate::{buffer::Buffer, symbol, Callback, Cmd, Widget};
use crossterm::event::MouseEvent;
use expanse::{
geometry::Size,
result::Layout,
style::{Dimension, PositionType, Style},
};
use std::{any::Any, fmt};
#[derive(Default, PartialEq)]
pub struct Radio<MSG> {
layout: Option<Layout>,
label: String,
is_checked: bool,
id: Option<String>,
on_input: Vec<Callback<Event, MSG>>,
}
impl<MSG> Radio<MSG> {
pub fn new<S>(label: S) -> Self
where
S: ToString,
{
Radio {
layout: None,
label: label.to_string(),
is_checked: false,
id: None,
on_input: vec![],
}
}
pub fn set_label<S: ToString>(&mut self, label: S) {
self.label = label.to_string();
}
pub fn set_checked(&mut self, checked: bool) {
self.is_checked = checked;
}
}
impl<MSG: 'static> Widget<MSG> for Radio<MSG> {
fn layout(&self) -> Option<&Layout> {
self.layout.as_ref()
}
fn set_layout(&mut self, layout: Layout) {
self.layout = Some(layout);
}
fn style(&self) -> Style {
Style {
position_type: PositionType::Relative,
size: Size {
width: Dimension::Points((self.label.len() + 3) as f32),
height: Dimension::Points(1.0),
},
min_size: Size {
height: Dimension::Points(1.0),
..Default::default()
},
..Default::default()
}
}
fn draw(&self, buf: &mut Buffer) -> Vec<Cmd> {
let layout = self.layout.expect("must have a layout");
let loc_x = layout.location.x.round() as usize;
let loc_y = layout.location.y.round() as usize;
let (box_symbol, x_offset) = if self.is_checked {
(symbol::RADIO_CHECKED, 0)
} else {
(symbol::RADIO_UNCHECKED, 0)
};
buf.set_symbol(loc_x, loc_y, box_symbol);
for (t, ch) in self.label.chars().enumerate() {
buf.set_symbol(loc_x + 3 + x_offset + t, loc_y, ch);
}
vec![]
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn set_size(&mut self, _width: Option<f32>, _height: Option<f32>) {}
fn process_event(&mut self, event: Event) -> Vec<MSG> {
match event {
Event::Mouse(MouseEvent::Down(_btn, _x, _y, _modifier)) => {
self.is_checked = !self.is_checked;
vec![]
}
_ => vec![],
}
}
fn set_id(&mut self, id: &str) {
self.id = Some(id.to_string());
}
fn get_id(&self) -> &Option<String> {
&self.id
}
}
impl<MSG> fmt::Debug for Radio<MSG> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Radio")
.field("label", &self.label)
.field("id", &self.id)
.finish()
}
}