1use crate::animation::animation::{ Animation, Vec2Animation, FadeAnimation };
2use crate::widget::Widget;
3use crate::graphics::Renderer;
4use crate::style::color::Color;
5use log::{ debug, info };
6use std::sync::Arc;
7use std::cell::RefCell;
8
9pub struct Button {
10 x: f32,
11 y: f32,
12 width: f32,
13 height: f32,
14 text: String,
15 font_size: f32,
16 background_color: Color,
17 text_color: Color,
18 border_color: Color,
19 border_width: f32, padding: f32, is_pressed: bool,
22 on_click: Option<Arc<RefCell<dyn FnMut() + 'static>>>,
23 pressed_background_color: Color,
24 pressed_border_color: Color,
25 pressed_text_color: Color,
26 is_hovered: bool,
27 hover_background_color: Color,
28 hover_border_color: Color,
29 hover_text_color: Color,
30 on_hover: Option<Arc<RefCell<dyn FnMut(bool) + 'static>>>,
31 position_animation: Option<Vec2Animation>,
32 fade_animation: Option<FadeAnimation>,
33 opacity: f32,
34}
35
36impl Button {
37 pub fn new(text: &str, renderer: &Renderer) -> Self {
38 debug!("Creating new Button with text: '{}'", text);
39 let background_color = Color::new(0.7, 0.7, 0.7, 1.0);
40 let border_color = Color::new(0.3, 0.3, 0.3, 1.0);
41 let text_color = Color::new(0.0, 0.0, 0.0, 1.0);
42
43 let mut btn = Self {
44 x: 0.0,
45 y: 0.0,
46 width: 0.0,
47 height: 0.0,
48 text: text.to_string(),
49 font_size: 32.0,
50 background_color,
51 text_color,
52 border_color,
53 border_width: 2.0, padding: 10.0, is_pressed: false,
56 on_click: None,
57 pressed_background_color: Color::new(0.6, 0.6, 0.6, 1.0),
58 pressed_border_color: Color::new(0.2, 0.2, 0.2, 1.0),
59 pressed_text_color: Color::new(0.0, 0.0, 0.0, 1.0),
60 is_hovered: false,
61 hover_background_color: Color::new(0.8, 0.8, 0.8, 1.0),
62 hover_border_color: Color::new(0.4, 0.4, 0.4, 1.0),
63 hover_text_color: Color::new(0.0, 0.0, 0.0, 1.0),
64 on_hover: None,
65 position_animation: None,
66 fade_animation: None,
67 opacity: 1.0,
68 };
69 btn.update_size(renderer);
70 info!("Button created with size: {}x{}", btn.width, btn.height);
71 btn
72 }
73
74 fn update_size(&mut self, renderer: &Renderer) {
75 let (text_width, text_height) = renderer
76 .text_renderer()
77 .font_renderer()
78 .calculate_text_size(&self.text, self.font_size);
79
80 self.width = text_width + self.padding * 2.0;
82 self.height = text_height + self.padding * 2.0;
83 debug!("Button size updated: {}x{}", self.width, self.height);
84 }
85
86 pub fn set_text(&mut self, text: &str, renderer: &Renderer) {
87 debug!("Button text changing from '{}' to '{}'", self.text, text);
88 self.text = text.to_string();
89 self.update_size(renderer);
90 }
91
92 pub fn set_font_size(&mut self, size: f32, renderer: &Renderer) {
93 debug!("Button font size changing from {} to {}", self.font_size, size);
94 self.font_size = size;
95 self.update_size(renderer);
96 }
97
98 pub fn set_background_color(&mut self, color: Color) {
99 self.background_color = color;
100 }
101
102 pub fn set_text_color(&mut self, color: Color) {
103 self.text_color = color;
104 }
105
106 pub fn set_border_color(&mut self, color: Color) {
107 self.border_color = color;
108 }
109
110 pub fn set_border_width(&mut self, width: f32) {
111 self.border_width = width;
112 }
113
114 pub fn set_padding(&mut self, padding: f32, renderer: &Renderer) {
115 self.padding = padding;
116 self.update_size(renderer);
117 }
118
119 pub fn set_on_click<F>(&mut self, callback: F) where F: FnMut() + 'static {
121 self.on_click = Some(Arc::new(RefCell::new(callback)));
122 }
123
124 pub fn set_pressed_background_color(&mut self, color: Color) {
126 self.pressed_background_color = color;
127 }
128
129 pub fn set_pressed_border_color(&mut self, color: Color) {
131 self.pressed_border_color = color;
132 }
133
134 pub fn set_pressed_text_color(&mut self, color: Color) {
136 self.pressed_text_color = color;
137 }
138
139 pub fn set_hover_background_color(&mut self, color: Color) {
141 self.hover_background_color = color;
142 }
143
144 pub fn set_hover_border_color(&mut self, color: Color) {
146 self.hover_border_color = color;
147 }
148
149 pub fn set_hover_text_color(&mut self, color: Color) {
151 self.hover_text_color = color;
152 }
153
154 pub fn set_on_hover<F>(&mut self, callback: F) where F: FnMut(bool) + 'static {
156 self.on_hover = Some(Arc::new(RefCell::new(callback)));
157 }
158
159 pub fn update_hover(&mut self, x: f32, y: f32) {
161 let was_hovered = self.is_hovered;
162 self.is_hovered = self.contains_point(x, y);
163
164 if was_hovered != self.is_hovered {
166 if let Some(callback) = &self.on_hover {
167 callback.borrow_mut()(self.is_hovered);
168 }
169 }
170 }
171
172 pub fn has_fade_animation(&self) -> bool {
173 self.fade_animation.is_some()
174 }
175}
176
177impl Widget for Button {
178 fn get_position(&self) -> (f32, f32) {
179 (self.x, self.y)
180 }
181
182 fn get_size(&self) -> (f32, f32) {
183 (self.width, self.height)
184 }
185
186 fn get_background_color(&self) -> Color {
187 self.background_color
188 }
189
190 fn get_text_color(&self) -> Color {
191 self.text_color
192 }
193
194 fn get_hover_background_color(&self) -> Color {
195 self.hover_background_color
196 }
197
198 fn get_hover_text_color(&self) -> Color {
199 self.hover_text_color
200 }
201
202 fn get_opacity(&self) -> f32 {
203 self.opacity
204 }
205
206 fn get_is_hovered(&self) -> bool {
207 self.is_hovered
208 }
209
210 fn get_is_pressed(&self) -> bool {
211 self.is_pressed
212 }
213
214 fn draw(&self, renderer: &mut Renderer, screen_width: f32, screen_height: f32) {
215 let (bg, border, text) = if self.is_pressed {
216 (self.pressed_background_color, self.pressed_border_color, self.pressed_text_color)
217 } else if self.is_hovered {
218 (self.hover_background_color, self.hover_border_color, self.hover_text_color)
219 } else {
220 (self.background_color, self.border_color, self.text_color)
221 };
222
223 let current_background = bg * self.opacity;
224 let current_border = border * self.opacity;
225 let current_text = text * self.opacity;
226
227 if self.border_width > 0.0 {
229 renderer.draw_rect(
230 self.x - self.border_width,
231 self.y - self.border_width,
232 self.width + self.border_width * 2.0,
233 self.height + self.border_width * 2.0,
234 current_border.to_array()
235 );
236 }
237
238 renderer.draw_rect(self.x, self.y, self.width, self.height, current_background.to_array());
239
240 let (text_width, text_height) = renderer
242 .text_renderer()
243 .font_renderer()
244 .calculate_text_size(&self.text, self.font_size);
245
246 let text_x = self.x + (self.width - text_width) / 2.0;
247 let text_y = self.y + (self.height - text_height) / 2.0;
248
249 renderer
250 .text_renderer_mut()
251 .render_text(
252 &self.text,
253 text_x,
254 text_y,
255 self.font_size,
256 screen_width,
257 screen_height,
258 current_text.to_array()
259 );
260 }
261
262 fn set_size(&mut self, width: f32, height: f32) {
263 self.width = width;
264 self.height = height;
265 }
266
267 fn position(&self) -> (f32, f32) {
268 (self.x, self.y)
269 }
270
271 fn size(&self) -> (f32, f32) {
272 (self.width, self.height)
273 }
274
275 fn set_position(&mut self, x: f32, y: f32) {
276 self.x = x;
277 self.y = y;
278 }
279
280 fn on_mouse_press(&mut self, _x: f32, _y: f32) -> bool {
281 if self.contains_point(_x, _y) {
282 self.is_pressed = true;
283 true
284 } else {
285 false
286 }
287 }
288
289 fn on_mouse_release(&mut self, x: f32, y: f32) -> bool {
290 if self.is_pressed {
291 self.is_pressed = false;
292 if self.contains_point(x, y) {
293 if let Some(callback) = &self.on_click {
295 callback.borrow_mut()();
296 }
297 return true;
298 }
299 }
300 false
301 }
302
303 fn set_on_click<F>(&mut self, callback: F) where F: FnMut() + 'static {
304 self.on_click = Some(Arc::new(RefCell::new(callback)));
305 }
306
307 fn set_on_hover<F>(&mut self, callback: F) where F: FnMut(bool) + 'static {
308 self.on_hover = Some(Arc::new(RefCell::new(callback)));
309 }
310
311 fn set_position_animation(&mut self, animation: Vec2Animation) {
312 self.position_animation = Some(animation);
313 }
314
315 fn set_fade_animation(&mut self, animation: FadeAnimation) {
316 self.fade_animation = Some(animation);
317 }
318
319 fn update_animations(&mut self, delta_time: f32) {
320 if let Some(ref mut anim) = self.position_animation {
322 anim.update(delta_time);
323 let pos = anim.value();
324 self.x = pos.x;
325 self.y = pos.y;
326
327 if anim.is_finished() {
328 self.position_animation = None;
329 }
330 }
331
332 if let Some(ref mut anim) = self.fade_animation {
334 anim.update(delta_time);
335 self.opacity = anim.value();
336
337 if anim.is_finished() {
338 self.fade_animation = None;
339 }
340 }
341 }
342}