1pub struct Switch {
2 pub pos_x: usize,
3 pub pos_y: usize,
4 pub width: usize,
5 pub height: usize,
6
7 pub on: bool,
8 anim_t: f32,
9 pub anim_speed: f32,
10
11 pub track_color_off: crate::color::Color,
12 pub track_color_on: crate::color::Color,
13 pub thumb_color: crate::color::Color,
14 pub thumb_padding: f32,
15
16 pub label: Option<crate::ui::text::Text>,
17 pub label_size: f32,
18 pub label_color: crate::color::Color,
19 pub label_gap: usize,
20
21 lmb_was_down: bool,
22 toggled_this_frame: bool,
23}
24
25impl Default for Switch {
26 fn default() -> Self {
27 Self {
28 pos_x: 0,
29 pos_y: 0,
30 width: 50,
31 height: 26,
32 on: false,
33 anim_t: 0.0,
34 anim_speed: 0.08,
35 track_color_off: crate::color::Color::new(120, 120, 130),
36 track_color_on: crate::color::Color::new(52, 199, 89),
37 thumb_color: crate::color::Color::new(255, 255, 255),
38 thumb_padding: 2.0,
39 label: None,
40 label_size: 14.0,
41 label_color: crate::color::Color::new(200, 200, 200),
42 label_gap: 10,
43 lmb_was_down: false,
44 toggled_this_frame: false,
45 }
46 }
47}
48
49impl Switch {
50 pub fn position(mut self, x: usize, y: usize) -> Self {
51 self.pos_x = x;
52 self.pos_y = y;
53 self
54 }
55
56 pub fn size(mut self, width: usize, height: usize) -> Self {
57 self.width = width;
58 self.height = height;
59 self
60 }
61
62 pub fn default_on(mut self, on: bool) -> Self {
63 self.on = on;
64 self.anim_t = if on { 1.0 } else { 0.0 };
65 self
66 }
67
68 pub fn anim_speed(mut self, speed: f32) -> Self {
69 self.anim_speed = speed;
70 self
71 }
72
73 pub fn track_color_off(mut self, color: crate::color::Color) -> Self {
74 self.track_color_off = color;
75 self
76 }
77
78 pub fn track_color_on(mut self, color: crate::color::Color) -> Self {
79 self.track_color_on = color;
80 self
81 }
82
83 pub fn thumb_color(mut self, color: crate::color::Color) -> Self {
84 self.thumb_color = color;
85 self
86 }
87
88 pub fn thumb_padding(mut self, padding: f32) -> Self {
89 self.thumb_padding = padding;
90 self
91 }
92
93 pub fn label(mut self, text: &str, font: crate::ttf::Font, size: f32) -> Self {
94 self.label = Some(crate::ui::text::Text::new(text, font));
95 self.label_size = size;
96 self
97 }
98
99 pub fn label_color(mut self, color: crate::color::Color) -> Self {
100 self.label_color = color;
101 self
102 }
103
104 pub fn label_gap(mut self, gap: usize) -> Self {
105 self.label_gap = gap;
106 self
107 }
108
109 pub fn is_on(&self) -> bool {
110 self.on
111 }
112
113 pub fn set_on(&mut self, on: bool) {
114 self.on = on;
115 }
116
117 pub fn just_toggled(&self) -> bool {
118 self.toggled_this_frame
119 }
120
121 fn update(&mut self, window: &mut crate::window::Window) {
122 self.toggled_this_frame = false;
123
124 let mouse = window.get_mouse_state();
125 let lmb = mouse.lmb_clicked;
126 let lmb_just_pressed = lmb && !self.lmb_was_down;
127
128 if lmb_just_pressed {
129 let mx = mouse.pos_x;
130 let my = mouse.pos_y;
131 let in_bounds = mx >= self.pos_x as f32
132 && mx < (self.pos_x + self.width) as f32
133 && my >= self.pos_y as f32
134 && my < (self.pos_y + self.height) as f32;
135
136 if in_bounds {
137 self.on = !self.on;
138 self.toggled_this_frame = true;
139 }
140 }
141
142 self.lmb_was_down = lmb;
143
144 let target = if self.on { 1.0 } else { 0.0 };
146 let diff = target - self.anim_t;
147 if diff.abs() > 0.001 {
148 self.anim_t += diff.signum() * self.anim_speed;
149 self.anim_t = self.anim_t.clamp(0.0, 1.0);
150 } else {
151 self.anim_t = target;
152 }
153 }
154
155 pub fn draw(&mut self, window: &mut crate::window::Window) {
156 self.update(window);
157
158 let track_color = self.track_color_off.lerp(&self.track_color_on, self.anim_t);
159 let radius = self.height / 2;
160
161 window.draw_rect_f(
163 self.pos_x, self.pos_y,
164 self.width, self.height,
165 radius,
166 &track_color,
167 0,
168 );
169
170 let thumb_radius = (self.height as f32 / 2.0) - self.thumb_padding;
172 let left_cx = self.pos_x as f32 + self.thumb_padding + thumb_radius;
173 let right_cx = self.pos_x as f32 + self.width as f32 - self.thumb_padding - thumb_radius;
174 let thumb_cx = left_cx + self.anim_t * (right_cx - left_cx);
175 let thumb_cy = self.pos_y as f32 + self.height as f32 / 2.0;
176
177 window.draw_ellipse_f(
179 thumb_cx as isize,
180 (thumb_cy + 1.0) as isize,
181 thumb_radius as usize, thumb_radius as usize,
182 &crate::color::Color::rgba(0, 0, 0, 30),
183 0,
184 );
185
186 window.draw_ellipse_f(
188 thumb_cx as isize,
189 thumb_cy as isize,
190 thumb_radius as usize, thumb_radius as usize,
191 &self.thumb_color,
192 0,
193 );
194
195 if let Some(ref label) = self.label {
197 let label_x = self.pos_x + self.width + self.label_gap;
198 let label_h = self.label_size;
199 let label_y = self.pos_y as f32 + (self.height as f32 - label_h) / 2.0;
200 window.draw_text(label_x, label_y as usize, label, self.label_size, &self.label_color);
201 }
202 }
203}