1use crate::{prelude::*, widget::conditional_widgets::ConditionalWidgets};
2
3use ascii_forge::prelude::*;
4
5use std::{collections::HashSet, io, time::Duration};
6
7pub struct Scene<D> {
8 window: Window,
9 data: D,
10 widgets: Vec<Box<dyn Widget<D>>>,
11 special_widgets: Vec<Box<dyn SpecialWidget<D>>>,
12}
13
14impl<D: 'static> Scene<D> {
15 pub fn new(window: Window, data: D) -> Self {
16 Self {
17 window,
18 data,
19 widgets: vec![],
20 special_widgets: vec![],
21 }
22 }
23
24 pub fn data(&self) -> &D {
25 &self.data
26 }
27
28 pub fn data_mut(&mut self) -> &mut D {
29 &mut self.data
30 }
31
32 pub fn insert_widget(&mut self, widget: impl Widget<D> + 'static) -> &mut Self {
33 self.widgets.push(Box::new(widget));
34 self
35 }
36
37 pub fn insert_widgets(&mut self, set: impl WidgetSet<D>) -> &mut Self {
38 set.insert(self);
39 self
40 }
41
42 pub fn insert_special_widget(&mut self, widget: impl SpecialWidget<D> + 'static) -> &mut Self {
43 self.special_widgets.push(Box::new(widget));
44 self
45 }
46
47 pub fn insert_conditional_widgets(
48 &mut self,
49 cond: impl Fn(&mut Window, &mut D) -> bool + 'static,
50 widgets: impl WidgetSet<D>,
51 ) -> &mut Self {
52 let start = self.widgets.len();
53 widgets.insert(self);
54 let end = self.widgets.len();
55
56 self.insert_special_widget(ConditionalWidgets::new(cond, (start..end).collect()));
57 self
58 }
59
60 pub fn take_all(self) -> (Window, D) {
61 (self.window, self.data)
62 }
63
64 pub fn update(&mut self) {
65 let mut updated = HashSet::default();
66 for special in &mut self.special_widgets {
67 special.update(
68 &mut self.window,
69 &mut self.data,
70 &mut self.widgets,
71 &mut updated,
72 );
73 }
74 for (i, widget) in self.widgets.iter_mut().enumerate() {
75 if updated.contains(&i) {
76 continue;
77 }
78
79 widget.update(&mut self.window, &mut self.data);
80 }
81 }
82
83 pub fn run(
84 &mut self,
85 update_millis: u64,
86 run_cond: impl Fn(&mut Self) -> bool,
87 ) -> io::Result<&mut Self> {
88 while run_cond(self) {
89 self.update();
90
91 self.window.update(Duration::from_millis(update_millis))?;
92 }
93 Ok(self)
94 }
95}