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 (row_no, row_selectables) in self.selectables.iter().enumerate() {
251 for (col_no, &(x, y)) in row_selectables.iter().enumerate() {
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((col_no, row_no)) {
260 let (mut clean, state) = self.split_clean();
261 return state.get_mut(x, y).mouse_event(
262 &mut clean,
263 col - chunk.x,
264 row - chunk.y,
265 col,
266 row,
267 );
268 }
269
270 if self.cursor.hover(&self.selectables) == Some((col_no, row_no)) {
271 return self.select().is_ok();
272 }
273
274 self.deselect().ok();
275 self.cursor = CursorState::to_hover((col_no, row_no));
276 return true;
277 }
278 }
279
280 self.deselect().ok();
281 self.cursor = CursorState::default();
282 true
283 }
284
285 pub fn message(&mut self, data: HashMap<String, Box<dyn Any>>) -> bool {
287 let selected = self.cursor.selected(&self.selectables);
288 let (mut frameworkclean, state) = self.split_clean();
289
290 if let Some((x, y)) = selected {
291 return state.get_mut(x, y).message(
292 &mut frameworkclean,
293 data
294 );
295 }
296
297 false
298 }
299
300 pub fn load(&mut self) -> Result<(), Box<dyn Error>> {
301 let selected = self.cursor.selected(&self.selectables);
302 let hover = self.cursor.hover(&self.selectables);
303 let (mut frameworkclean, state) = self.split_clean();
304
305 for (y, row) in state.0.iter_mut().enumerate() {
306 for (x, row_item) in row.items.iter_mut().enumerate() {
307 row_item.item.load_item(
308 &mut frameworkclean,
309 ItemInfo {
310 selected: Some((x, y)) == selected,
311 hover: Some((x, y)) == hover,
312 x,
313 y,
314 },
315 )?;
316 }
317 }
318
319 Ok(())
320 }
321
322 pub fn load_only(&mut self, x: usize, y: usize) -> Result<(), Box<dyn Error>> {
323 let selected = self.cursor.selected(&self.selectables);
324 let hover = self.cursor.hover(&self.selectables);
325 let (mut frameworkclean, state) = self.split_clean();
326
327 state.get_mut(x, y).load_item(
328 &mut frameworkclean,
329 ItemInfo {
330 selected: Some((x, y)) == selected,
331 hover: Some((x, y)) == hover,
332 x,
333 y,
334 },
335 )
336 }
337
338 pub fn load_only_multiple(&mut self, locations: &[(usize, usize)]) {
339 let selected = self.cursor.selected(&self.selectables);
340 let hover = self.cursor.hover(&self.selectables);
341 let (mut frameworkclean, state) = self.split_clean();
342
343 locations.iter().for_each(|(x, y)| {
344 let _ = state.get_mut(*x, *y).load_item(
345 &mut frameworkclean,
346 ItemInfo {
347 selected: Some((*x, *y)) == selected,
348 hover: Some((*x, *y)) == hover,
349 x: *x,
350 y: *y,
351 },
352 );
353 })
354 }
355}
356
357impl Framework {
358 pub fn split_clean(&mut self) -> (FrameworkClean, &mut State) {
360 self.into()
361 }
362}
363
364impl Framework {
365 pub fn r#move(&mut self, direction: FrameworkDirection) -> Result<(), FrameworkError> {
368 self.cursor.r#move(direction, &self.selectables)
369 }
370
371 pub fn select(&mut self) -> Result<(), Box<dyn Error>> {
373 if let Some((x, y)) = self.cursor.hover(&self.selectables) {
374 let (mut frameworkclean, state) = self.split_clean();
375 let item = state.get_mut(x, y);
376 if item.select(&mut frameworkclean) {
377 self.cursor.select()?;
378 }
379 } else {
380 Err(FrameworkError::CursorStateMismatch)?;
381 }
382
383 Ok(())
384 }
385
386 pub fn deselect(&mut self) -> Result<(), Box<dyn Error>> {
388 if let Some((x, y)) = self.cursor.selected(&self.selectables) {
389 let (mut frameworkclean, state) = self.split_clean();
390 let item = state.get_mut(x, y);
391 if item.deselect(&mut frameworkclean) {
392 self.cursor.deselect()?;
393 }
394 } else {
395 Err(FrameworkError::CursorStateMismatch)?;
396 }
397
398 Ok(())
399 }
400}
401
402#[derive(Debug)]
404pub enum FrameworkError {
405 MoveSelected,
407 CursorStateMismatch,
409 NoSuchSave,
411}
412
413impl Display for FrameworkError {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 f.write_fmt(format_args!("{:?}", self))
416 }
417}
418
419impl Error for FrameworkError {}