1use log::debug;
2
3use crate::animation::animation::{ FadeAnimation, Vec2Animation };
4use crate::graphics::Renderer;
5use crate::style::color::Color;
6use crate::widget::Widget;
7use crate::Animation;
8use std::cell::RefCell;
9use std::sync::Arc;
10
11#[derive(Debug)]
12pub enum ShapeType {
13 Rectangle,
14 Circle,
15 Triangle,
16}
17
18pub struct Shape {
19 x: f32,
20 y: f32,
21 width: f32,
22 height: f32,
23 shape_type: ShapeType,
24 fill_color: Color,
25 border_color: Color,
26 border_width: f32,
27 opacity: f32,
28 is_hovered: bool,
29 is_pressed: bool,
30 position_animation: Option<Vec2Animation>,
31 fade_animation: Option<FadeAnimation>,
32 on_hover: Option<Arc<RefCell<dyn FnMut(bool) + 'static>>>,
33 on_click: Option<Arc<RefCell<dyn FnMut() + 'static>>>,
34}
35
36impl Shape {
37 pub fn new(shape_type: ShapeType) -> Self {
38 debug!("Creating new shape: {:?}", shape_type);
39 Self {
40 x: 0.0,
41 y: 0.0,
42 width: 100.0,
43 height: 100.0,
44 shape_type,
45 fill_color: Color::new(1.0, 1.0, 1.0, 1.0),
46 border_color: Color::new(0.0, 0.0, 0.0, 1.0),
47 border_width: 0.0,
48 opacity: 1.0,
49 is_hovered: false,
50 is_pressed: false,
51 position_animation: None,
52 fade_animation: None,
53 on_hover: None,
54 on_click: None,
55 }
56 }
57
58 pub fn set_fill_color(&mut self, color: Color) {
59 debug!("Setting fill color: {:?}", color);
60 self.fill_color = color;
61 }
62
63 pub fn set_border_color(&mut self, color: Color) {
64 debug!("Setting border color: {:?}", color);
65 self.border_color = color;
66 }
67
68 pub fn set_border_width(&mut self, width: f32) {
69 debug!("Setting border width: {}", width);
70 self.border_width = width;
71 }
72
73 pub fn update_hover(&mut self, x: f32, y: f32) {
75 let was_hovered = self.is_hovered;
77
78 let is_now_hovered = self.contains_point(x, y);
80 if was_hovered == is_now_hovered {
81 return;
82 }
83
84 self.is_hovered = is_now_hovered;
85 if let Some(callback) = &self.on_hover {
86 callback.borrow_mut()(self.is_hovered);
87 }
88 }
89
90 pub fn has_fade_animation(&self) -> bool {
91 self.fade_animation.is_some()
92 }
93
94 pub fn has_position_animation(&self) -> bool {
95 self.position_animation.is_some()
96 }
97}
98
99impl Widget for Shape {
100 fn draw(&self, renderer: &mut Renderer, _screen_width: f32, _screen_height: f32) {
101 let fill_color = self.fill_color.with_opacity(self.opacity);
103 let border_color = self.border_color.with_opacity(self.opacity);
104
105 match self.shape_type {
106 ShapeType::Rectangle => {
107 if self.border_width > 0.0 {
109 renderer.draw_rect(
110 self.x - self.border_width,
111 self.y - self.border_width,
112 self.width + self.border_width * 2.0,
113 self.height + self.border_width * 2.0,
114 border_color.to_array()
115 );
116 }
117 renderer.draw_rect(self.x, self.y, self.width, self.height, fill_color.to_array());
119 }
120 ShapeType::Circle => {
121 self.draw_circle_with_opacity(renderer, fill_color, border_color)
122 }
123 ShapeType::Triangle => {
124 self.draw_triangle_with_opacity(renderer, fill_color, border_color)
125 }
126 }
127 }
128
129 fn get_position(&self) -> (f32, f32) {
131 (self.x, self.y)
132 }
133 fn get_size(&self) -> (f32, f32) {
134 (self.width, self.height)
135 }
136 fn get_background_color(&self) -> Color {
137 self.fill_color
138 }
139 fn get_text_color(&self) -> Color {
140 Color::new(0.0, 0.0, 0.0, 0.0)
141 }
142 fn get_hover_background_color(&self) -> Color {
143 self.fill_color
144 }
145 fn get_hover_text_color(&self) -> Color {
146 Color::new(0.0, 0.0, 0.0, 0.0)
147 }
148 fn get_opacity(&self) -> f32 {
149 self.opacity
150 }
151 fn get_is_hovered(&self) -> bool {
152 self.is_hovered
153 }
154 fn get_is_pressed(&self) -> bool {
155 self.is_pressed
156 }
157 fn set_position(&mut self, x: f32, y: f32) {
158 self.x = x;
159 self.y = y;
160 }
161 fn set_size(&mut self, width: f32, height: f32) {
162 self.width = width;
163 self.height = height;
164 }
165 fn position(&self) -> (f32, f32) {
166 (self.x, self.y)
167 }
168 fn size(&self) -> (f32, f32) {
169 (self.width, self.height)
170 }
171
172 fn set_position_animation(&mut self, animation: Vec2Animation) {
173 self.position_animation = Some(animation);
174 }
175
176 fn set_fade_animation(&mut self, animation: FadeAnimation) {
177 self.fade_animation = Some(animation);
178 }
179
180 fn set_on_click<F>(&mut self, callback: F) where F: FnMut() + 'static {
181 self.on_click = Some(Arc::new(RefCell::new(callback)));
182 }
183
184 fn set_on_hover<F>(&mut self, callback: F) where F: FnMut(bool) + 'static {
185 self.on_hover = Some(Arc::new(RefCell::new(callback)));
186 }
187
188 fn on_mouse_press(&mut self, x: f32, y: f32) -> bool {
189 if self.contains_point(x, y) {
190 self.is_pressed = true;
191 true
192 } else {
193 false
194 }
195 }
196
197 fn on_mouse_release(&mut self, x: f32, y: f32) -> bool {
198 if self.is_pressed && self.contains_point(x, y) {
199 if let Some(callback) = &self.on_click {
200 callback.borrow_mut()();
201 }
202 true
203 } else {
204 false
205 }
206 }
207
208 fn update_animations(&mut self, delta_time: f32) {
209 if let Some(ref mut anim) = self.position_animation {
211 anim.update(delta_time);
212 let pos = anim.value();
213 self.x = pos.x;
214 self.y = pos.y;
215
216 if anim.is_finished() {
217 self.position_animation = None;
218 }
219 }
220
221 if let Some(ref mut anim) = self.fade_animation {
223 anim.update(delta_time);
224 self.opacity = anim.value();
225
226 if anim.is_finished() {
227 self.fade_animation = None;
228 }
229 }
230 }
231}
232
233impl Shape {
234 fn draw_circle_with_opacity(
235 &self,
236 renderer: &mut Renderer,
237 fill_color: Color,
238 border_color: Color
239 ) {
240 let center_x = self.x + self.width / 2.0;
241 let center_y = self.y + self.height / 2.0;
242 let radius = self.width.min(self.height) / 2.0;
243
244 if self.border_width > 0.0 {
246 renderer.draw_circle(
247 center_x,
248 center_y,
249 radius + self.border_width,
250 border_color.to_array()
251 );
252 }
253
254 renderer.draw_circle(center_x, center_y, radius, fill_color.to_array());
256 }
257
258 fn draw_triangle_with_opacity(
259 &self,
260 renderer: &mut Renderer,
261 fill_color: Color,
262 border_color: Color
263 ) {
264 let vertices = [
265 (self.x, self.y + self.height),
266 (self.x + self.width, self.y + self.height),
267 (self.x + self.width / 2.0, self.y),
268 ];
269
270 if self.border_width > 0.0 {
272 let border_vertices = [
273 (vertices[0].0 - self.border_width, vertices[0].1 + self.border_width),
274 (vertices[1].0 + self.border_width, vertices[1].1 + self.border_width),
275 (vertices[2].0, vertices[2].1 - self.border_width),
276 ];
277 renderer.draw_triangle(border_vertices, border_color.to_array());
278 }
279
280 renderer.draw_triangle(vertices, fill_color.to_array());
281 }
282}