1use std::{any::Any, collections::HashMap, error::Error, fmt::Display};
2
3use crossterm::event::KeyEvent;
4use ratatui::{layout::Rect, Frame};
5
6use super::{
7 CursorState, FrameworkClean, FrameworkData, FrameworkDirection, FrameworkHistory, ItemInfo,
8 State,
9};
10
11#[derive(Clone)]
17pub struct Framework {
18 pub selectables: Vec<Vec<(usize, usize)>>,
20 pub data: FrameworkData,
22 pub state: State,
24 pub cursor: CursorState,
26 pub history: Vec<FrameworkHistory>,
28 pub frame_area: Option<Rect>,
30}
31
32impl Framework {
33 pub fn clear_history(&mut self) {
35 self.history.clear();
36 }
37
38 pub fn push_history(&mut self) {
40 self.history.push(FrameworkHistory {
41 selectables: self.selectables.clone(),
42 data: self.data.state.clone(),
43 state: self.state.clone(),
44 cursor: self.cursor,
45 });
46 }
47
48 pub fn pop_history(&mut self) -> Option<FrameworkHistory> {
50 self.history.pop()
51 }
52
53 pub fn revert_last_history(&mut self) -> Result<(), FrameworkError> {
55 let history = match self.history.pop() {
56 None => return Err(FrameworkError::NoSuchSave),
57 Some(history) => history,
58 };
59
60 self.selectables = history.selectables;
61 self.data.state = history.data;
62 self.state = history.state;
63 self.cursor = history.cursor;
64
65 Ok(())
66 }
67
68 pub fn revert_history(&mut self, index: usize) -> Result<(), FrameworkError> {
70 if index >= self.history.len() {
71 return Err(FrameworkError::NoSuchSave);
72 }
73
74 let history = self.history.remove(index);
75
76 self.selectables = history.selectables;
77 self.data.state = history.data;
78 self.state = history.state;
79 self.cursor = history.cursor;
80
81 Ok(())
82 }
83}
84
85impl Framework {
86 pub fn is_selected(&self) -> bool {
87 self.cursor.is_selected()
88 }
89
90 pub fn is_hover(&self) -> bool {
91 self.cursor.is_hover()
92 }
93
94 pub fn is_none(&self) -> bool {
95 self.cursor.is_none()
96 }
97}
98
99impl Framework {
100 pub fn new(state: State) -> Self {
102 Self {
103 selectables: state.selectables(),
104 data: FrameworkData::default(),
105 state,
106 frame_area: None,
107 cursor: CursorState::default(),
108 history: Vec::new(),
109 }
110 }
111
112 pub fn set_state(&mut self, state: State) {
114 self.state = state;
115 self.selectables = self.state.selectables();
116 }
117
118 pub fn render(&mut self, frame: &mut Frame) {
120 let area = frame.area();
121 self.frame_area = Some(area);
122
123 let chunks = self.state.get_chunks(area);
124
125 let selected = self.cursor.selected(&self.selectables);
126 let hover = self.cursor.hover(&self.selectables);
127
128 self.render_raw(frame, &chunks, selected, hover, false);
130 self.render_raw(frame, &chunks, selected, hover, true);
131 }
132
133 pub fn render_raw(
135 &mut self,
136 frame: &mut Frame,
137 chunks: &[Vec<Rect>],
138 selected: Option<(usize, usize)>,
139 hover: Option<(usize, usize)>,
140 popup_render: bool,
141 ) {
142 let (mut frameworkclean, state) = self.split_clean();
143
144 for (y, (row, row_chunks)) in state.0.iter_mut().zip(chunks.iter()).enumerate() {
145 for (x, (row_item, item_chunk)) in
146 row.items.iter_mut().zip(row_chunks.iter()).enumerate()
147 {
148 row_item.item.render(
149 frame,
150 &mut frameworkclean,
151 *item_chunk,
152 popup_render,
155 ItemInfo {
156 selected: Some((x, y)) == selected,
157 hover: Some((x, y)) == hover,
158 x,
159 y,
160 },
161 );
162 }
163 }
164 }
165
166 pub fn render_only(&mut self, frame: &mut Frame, x: usize, y: usize) {
168 let chunk = self.state.get_chunks(frame.area())[y][x];
169
170 let selected = self.cursor.selected(&self.selectables);
171 let hover = self.cursor.hover(&self.selectables);
172
173 self.render_only_raw(frame, x, y, chunk, false, selected, hover);
174 self.render_only_raw(frame, x, y, chunk, true, selected, hover);
175 }
176
177 pub fn render_only_multiple(&mut self, frame: &mut Frame, locations: &[(usize, usize)]) {
181 let chunks = self.state.get_chunks(frame.area());
182
183 let selected = self.cursor.selected(&self.selectables);
184 let hover = self.cursor.hover(&self.selectables);
185
186 locations.iter().for_each(|(x, y)| {
187 self.render_only_raw(frame, *x, *y, chunks[*y][*x], false, selected, hover);
188 });
189
190 locations.iter().for_each(|(x, y)| {
191 self.render_only_raw(frame, *x, *y, chunks[*y][*x], true, selected, hover);
192 });
193 }
194
195 pub fn render_only_raw(
197 &mut self,
198 frame: &mut Frame,
199 x: usize,
200 y: usize,
201 chunk: Rect,
202 popup_render: bool,
203 selected: Option<(usize, usize)>,
204 hover: Option<(usize, usize)>,
205 ) {
206 let (mut frameworkclean, state) = self.split_clean();
207 state.get_mut(x, y).render(
208 frame,
209 &mut frameworkclean,
210 chunk,
211 popup_render,
212 ItemInfo {
213 selected: selected == Some((x, y)),
214 hover: hover == Some((x, y)),
215 x,
216 y,
217 },
218 )
219 }
220
221 pub fn key_input(&mut self, key: KeyEvent) -> Result<(), Box<dyn Error>> {
223 let selected = self.cursor.selected(&self.selectables);
224 let (mut frameworkclean, state) = self.split_clean();
225
226 if let Some((x, y)) = selected {
227 state.get_mut(x, y).key_event(
228 &mut frameworkclean,
229 key,
230 ItemInfo {
231 selected: true,
232 hover: false,
233 x,
234 y,
235 },
236 )?;
237 }
238
239 Ok(())
240 }
241
242 pub fn mouse_event(&mut self, col: u16, row: u16) -> bool {
244 let chunks = match self.frame_area {
245 Some(area) => self.state.get_chunks(area),
246 None => return false,
247 };
248
249 for (y, row_items) in self.state.0.iter().enumerate() {
251 for x in 0..row_items.items.len() {
252 let chunk = chunks[y][x];
253 if !chunk.intersects(Rect::new(col, row, 1, 1)) {
255 continue;
256 }
257
258 if self.cursor.selected(&self.selectables) == Some((x, y)) {
260 let (mut clean, state) = self.split_clean();
261 let a = state.get_mut(x, y).mouse_passthrough(
262 &mut clean,
263 true,
264 col - chunk.x,
265 row - chunk.y,
266 col,
267 row,
268 );
269 let b = state.get_mut(x, y).mouse_event(
270 &mut clean,
271 col - chunk.x,
272 row - chunk.y,
273 col,
274 row,
275 );
276 return a || b;
277 } else {
278 let (mut clean, state) = self.split_clean();
279 state.get_mut(x, y).mouse_passthrough(
280 &mut clean,
281 false,
282 col - chunk.x,
283 row - chunk.y,
284 col,
285 row,
286 );
287 }
288
289 if self.cursor.hover(&self.selectables) == Some((x, y)) {
290 return self.select().is_ok();
291 }
292
293 let mut selectable_index = None;
294
295 for (sel_row, row_items) in self.selectables.iter().enumerate() {
296 for (sel_col, (x2, y2)) in row_items.iter().enumerate() {
297 if (x2, y2) == (&x, &y) {
298 selectable_index = Some((sel_col, sel_row))
299 }
300 }
301 }
302
303 if let Some(sel_index) = selectable_index {
304 self.deselect().ok();
305 self.cursor = CursorState::to_hover(sel_index);
306 }
307
308 return true;
309 }
310 }
311
312 self.deselect().ok();
313 self.cursor = CursorState::default();
314 true
315 }
316
317 pub fn message(&mut self, data: HashMap<String, Box<dyn Any>>) -> bool {
319 let selected = self.cursor.selected(&self.selectables);
320 let (mut frameworkclean, state) = self.split_clean();
321
322 if let Some((x, y)) = selected {
323 return state.get_mut(x, y).message(&mut frameworkclean, data);
324 }
325
326 false
327 }
328
329 pub fn load(&mut self) -> Result<(), Box<dyn Error>> {
330 let selected = self.cursor.selected(&self.selectables);
331 let hover = self.cursor.hover(&self.selectables);
332 let (mut frameworkclean, state) = self.split_clean();
333
334 for (y, row) in state.0.iter_mut().enumerate() {
335 for (x, row_item) in row.items.iter_mut().enumerate() {
336 row_item.item.load_item(
337 &mut frameworkclean,
338 ItemInfo {
339 selected: Some((x, y)) == selected,
340 hover: Some((x, y)) == hover,
341 x,
342 y,
343 },
344 )?;
345 }
346 }
347
348 Ok(())
349 }
350
351 pub fn load_only(&mut self, x: usize, y: usize) -> Result<(), Box<dyn Error>> {
352 let selected = self.cursor.selected(&self.selectables);
353 let hover = self.cursor.hover(&self.selectables);
354 let (mut frameworkclean, state) = self.split_clean();
355
356 state.get_mut(x, y).load_item(
357 &mut frameworkclean,
358 ItemInfo {
359 selected: Some((x, y)) == selected,
360 hover: Some((x, y)) == hover,
361 x,
362 y,
363 },
364 )
365 }
366
367 pub fn load_only_multiple(&mut self, locations: &[(usize, usize)]) {
368 let selected = self.cursor.selected(&self.selectables);
369 let hover = self.cursor.hover(&self.selectables);
370 let (mut frameworkclean, state) = self.split_clean();
371
372 locations.iter().for_each(|(x, y)| {
373 let _ = state.get_mut(*x, *y).load_item(
374 &mut frameworkclean,
375 ItemInfo {
376 selected: Some((*x, *y)) == selected,
377 hover: Some((*x, *y)) == hover,
378 x: *x,
379 y: *y,
380 },
381 );
382 })
383 }
384}
385
386impl Framework {
387 pub fn split_clean(&mut self) -> (FrameworkClean<'_>, &mut State) {
389 self.into()
390 }
391}
392
393impl Framework {
394 pub fn r#move(&mut self, direction: FrameworkDirection) -> Result<(), FrameworkError> {
397 self.cursor.r#move(direction, &self.selectables)
398 }
399
400 pub fn select(&mut self) -> Result<(), Box<dyn Error>> {
402 if let Some((x, y)) = self.cursor.hover(&self.selectables) {
403 let (mut frameworkclean, state) = self.split_clean();
404 let item = state.get_mut(x, y);
405 if item.select(&mut frameworkclean) {
406 self.cursor.select()?;
407 }
408 } else {
409 Err(FrameworkError::CursorStateMismatch)?;
410 }
411
412 Ok(())
413 }
414
415 pub fn deselect(&mut self) -> Result<(), Box<dyn Error>> {
417 if let Some((x, y)) = self.cursor.selected(&self.selectables) {
418 let (mut frameworkclean, state) = self.split_clean();
419 let item = state.get_mut(x, y);
420 if item.deselect(&mut frameworkclean) {
421 self.cursor.deselect()?;
422 }
423 } else {
424 Err(FrameworkError::CursorStateMismatch)?;
425 }
426
427 Ok(())
428 }
429}
430
431#[derive(Debug)]
433pub enum FrameworkError {
434 MoveSelected,
436 CursorStateMismatch,
438 NoSuchSave,
440}
441
442impl Display for FrameworkError {
443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
444 f.write_fmt(format_args!("{:?}", self))
445 }
446}
447
448impl Error for FrameworkError {}