1use crate::render::callbacks::CallbackRegistry;
17use crate::render::widget::*;
18use crate::render::widget_cache::WidgetContainer;
19use crate::render::widget_config::*;
20use crate::render::{
21 inverse_color, make_points, make_size, Points, Size, POINT_X, POINT_Y, SIZE_HEIGHT, SIZE_WIDTH,
22};
23
24use sdl2::render::{Canvas, Texture};
25use sdl2::video::Window;
26
27use crate::render::layout_cache::LayoutContainer;
28use crate::render::texture_cache::TextureCache;
29use crate::render::texture_store::TextureStore;
30use crate::widgets::text_widget::{TextJustify, TextWidget};
31use sdl2::pixels::Color;
32use sdl2::rect::Rect;
33use std::any::Any;
34use std::collections::HashMap;
35
36pub type OnClickedCallbackType =
39 Option<Box<dyn FnMut(&mut TileWidget, &[WidgetContainer], &[LayoutContainer], bool)>>;
40
41pub struct TileWidget {
43 config: WidgetConfig,
44 system_properties: HashMap<i32, String>,
45 callback_registry: CallbackRegistry,
46 texture_store: TextureStore,
47 on_click: OnClickedCallbackType,
48 base_widget: BaseWidget,
49 text_widget: TextWidget,
50 image_name: String,
51 selected: bool,
52 hovered: bool,
53 originated: bool,
54}
55
56impl TileWidget {
58 pub fn new(points: Points, size: Size, image_name: String, tile_text: String) -> Self {
61 let mut base_widget = BaseWidget::new(points.clone(), size.clone());
62 let mut text_widget = TextWidget::new(
63 String::from("assets/OpenSans-Regular.ttf"),
64 sdl2::ttf::FontStyle::NORMAL,
65 14,
66 TextJustify::Center,
67 tile_text,
68 make_points(
69 points[POINT_X] + 1,
70 points[POINT_Y] + size[SIZE_HEIGHT] as i32 - 19,
71 ),
72 make_size(size[SIZE_WIDTH] - 2, 18),
73 );
74
75 base_widget.set_color(CONFIG_COLOR_BORDER, Color::RGB(0, 0, 0));
76 base_widget.set_numeric(CONFIG_BORDER_WIDTH, 1);
77 base_widget.set_color(CONFIG_COLOR_BASE, Color::RGB(255, 255, 255));
78 text_widget.set_color(CONFIG_COLOR_BASE, Color::RGBA(255, 255, 255, 255));
79 text_widget.set_color(CONFIG_COLOR_TEXT, Color::RGB(0, 0, 0));
80
81 Self {
82 config: WidgetConfig::new(points, size),
83 system_properties: HashMap::new(),
84 callback_registry: CallbackRegistry::new(),
85 texture_store: TextureStore::default(),
86 on_click: None,
87 base_widget,
88 text_widget,
89 image_name,
90 selected: false,
91 hovered: false,
92 originated: false,
93 }
94 }
95
96 pub fn on_click<F>(&mut self, callback: F)
98 where
99 F: FnMut(&mut TileWidget, &[WidgetContainer], &[LayoutContainer], bool) + 'static,
100 {
101 self.on_click = Some(Box::new(callback));
102 }
103
104 fn call_click_callback(
106 &mut self,
107 widgets: &[WidgetContainer],
108 layouts: &[LayoutContainer],
109 state: bool,
110 ) {
111 if let Some(mut cb) = self.on_click.take() {
112 cb(self, widgets, layouts, state);
113 self.on_click = Some(cb);
114 }
115 }
116
117 fn adjust_widgets(&mut self) {
118 if self.selected {
119 let selected_color = self.get_color(CONFIG_COLOR_SELECTED);
120 self.base_widget
121 .set_color(CONFIG_COLOR_BASE, selected_color);
122 self.text_widget
123 .set_color(CONFIG_COLOR_BASE, selected_color);
124 self.text_widget
125 .set_color(CONFIG_COLOR_TEXT, inverse_color(selected_color));
126 } else if self.hovered {
127 let hover_color = self.get_color(CONFIG_COLOR_HOVER);
128 self.base_widget.set_color(CONFIG_COLOR_BASE, hover_color);
129 self.text_widget.set_color(CONFIG_COLOR_BASE, hover_color);
130 self.text_widget
131 .set_color(CONFIG_COLOR_TEXT, inverse_color(hover_color));
132 } else {
133 self.base_widget
134 .set_color(CONFIG_COLOR_BASE, Color::RGB(255, 255, 255));
135 self.text_widget
136 .set_color(CONFIG_COLOR_BASE, Color::RGB(255, 255, 255));
137 self.text_widget
138 .set_color(CONFIG_COLOR_TEXT, Color::RGB(0, 0, 0));
139 }
140 }
141}
142
143impl Widget for TileWidget {
145 fn draw(&mut self, c: &mut Canvas<Window>, t: &mut TextureCache) -> Option<&Texture> {
146 if self.get_config().invalidated() {
147 let bounds = self.get_config().get_size(CONFIG_SIZE);
148 let base_color = self.get_color(CONFIG_COLOR_BASE);
149
150 self.texture_store
151 .create_or_resize_texture(c, bounds[0] as u32, bounds[1] as u32);
152
153 self.adjust_widgets();
154
155 let base_widget_texture = self.base_widget.draw(c, t).unwrap();
156 let text_widget_texture = self.text_widget.draw(c, t).unwrap();
157 let image_texture = t.get_image(c, self.image_name.clone());
158
159 c.with_texture_canvas(self.texture_store.get_mut_ref(), |texture| {
160 texture.set_draw_color(base_color);
161 texture.clear();
162
163 let size_center = bounds[SIZE_WIDTH] / 2;
164
165 texture
166 .copy(
167 base_widget_texture,
168 None,
169 Rect::new(0, 0, bounds[0], bounds[1]),
170 )
171 .unwrap();
172
173 texture
174 .copy(
175 text_widget_texture,
176 None,
177 Rect::new(
178 1,
179 bounds[SIZE_HEIGHT] as i32 - 20,
180 bounds[SIZE_WIDTH] - 2,
181 18,
182 ),
183 )
184 .unwrap();
185
186 texture
187 .copy(
188 image_texture,
189 None,
190 Rect::new(
191 (size_center - 16) as i32,
192 (bounds[SIZE_HEIGHT] / 2 - 32) as i32,
193 32,
194 32,
195 ),
196 )
197 .unwrap();
198 })
199 .unwrap();
200 }
201
202 self.texture_store.get_optional_ref()
203 }
204
205 fn mouse_entered(&mut self, _widgets: &[WidgetContainer], _layouts: &[LayoutContainer]) {
208 self.hovered = true;
209 self.get_config().set_invalidated(true);
210 }
211
212 fn mouse_exited(&mut self, _widgets: &[WidgetContainer], _layouts: &[LayoutContainer]) {
215 self.hovered = false;
216 self.get_config().set_invalidated(true);
217 }
218
219 fn button_clicked(
220 &mut self,
221 _widgets: &[WidgetContainer],
222 _layouts: &[LayoutContainer],
223 _button: u8,
224 _clicks: u8,
225 _state: bool,
226 ) {
227 if _button == 1 {
228 if _state {
229 self.originated = true;
230 } else {
231 if self.originated && self.hovered {
232 self.selected = !self.selected;
233 self.call_click_callback(_widgets, _layouts, self.selected);
234 }
235
236 self.originated = false;
237 }
238 }
239 }
240
241 default_widget_functions!();
242 default_widget_properties!();
243 default_widget_callbacks!();
244}