cog_task/action/core/
stack.rs

1use crate::action::{
2    Action, ActionSignal, Props, StatefulAction, StatefulNil, DEFAULT, INFINITE, VISUAL,
3};
4use crate::comm::{QWriter, Signal, SignalId};
5use crate::resource::{IoManager, ResourceAddr, ResourceManager};
6use crate::server::{AsyncSignal, Config, State, SyncSignal};
7use eframe::egui;
8use egui_extras::{Size, StripBuilder};
9use eyre::{eyre, Result};
10use itertools::Itertools;
11use serde::{Deserialize, Serialize};
12use std::collections::BTreeSet;
13
14#[derive(Debug, Deserialize, Serialize)]
15pub struct Stack(
16    Vec<Box<dyn Action>>,
17    #[serde(default)] Direction,
18    #[serde(default)] Vec<f32>,
19);
20
21stateful!(Stack {
22    children: Vec<Box<dyn StatefulAction>>,
23    direction: Direction,
24    active: Vec<bool>,
25    proportions: Vec<f32>,
26});
27
28#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
29pub enum Direction {
30    Horizontal,
31    Vertical,
32}
33
34impl Default for Direction {
35    fn default() -> Self {
36        Self::Horizontal
37    }
38}
39
40impl Stack {
41    pub fn new(children: Vec<Box<dyn Action>>, dir: Direction, proportions: Vec<f32>) -> Self {
42        Self(children, dir, proportions)
43    }
44}
45
46impl Action for Stack {
47    fn init(self) -> Result<Box<dyn Action>>
48    where
49        Self: 'static + Sized,
50    {
51        if !self.2.is_empty() && self.2.len() != self.0.len() {
52            return Err(eyre!(
53                "Stack should have same number of proportions and children."
54            ));
55        }
56
57        if self.2.iter().sum::<f32>() > 1.0 {
58            return Err(eyre!("Sum of Stack proportions cannot be greater than 1."));
59        }
60
61        Ok(Box::new(self))
62    }
63
64    #[inline]
65    fn in_signals(&self) -> BTreeSet<SignalId> {
66        let mut signals = BTreeSet::new();
67        for c in self.0.iter() {
68            signals.extend(c.in_signals());
69        }
70        signals
71    }
72
73    #[inline]
74    fn out_signals(&self) -> BTreeSet<SignalId> {
75        let mut signals = BTreeSet::new();
76        for c in self.0.iter() {
77            signals.extend(c.out_signals());
78        }
79        signals
80    }
81
82    #[inline]
83    fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
84        self.0
85            .iter()
86            .flat_map(|c| c.resources(config))
87            .unique()
88            .collect()
89    }
90
91    fn stateful(
92        &self,
93        io: &IoManager,
94        res: &ResourceManager,
95        config: &Config,
96        sync_writer: &QWriter<SyncSignal>,
97        async_writer: &QWriter<AsyncSignal>,
98    ) -> Result<Box<dyn StatefulAction>> {
99        let mut children = vec![];
100        for c in self.0.iter() {
101            children.push(c.stateful(io, res, config, sync_writer, async_writer)?);
102        }
103
104        let active = (0..children.len() as usize).map(|_| true).collect();
105
106        let proportions = if self.2.is_empty() {
107            let count = self.0.len();
108            (0..count).map(|_| 1.0 / count as f32).collect()
109        } else {
110            self.2.clone()
111        };
112
113        Ok(Box::new(StatefulStack {
114            done: false,
115            children,
116            direction: self.1,
117            active,
118            proportions,
119        }))
120    }
121}
122
123impl StatefulAction for StatefulStack {
124    impl_stateful!();
125
126    #[inline]
127    fn props(&self) -> Props {
128        let mut props = DEFAULT;
129
130        for c in self.children.iter() {
131            let c = c.props();
132            if c.visual() {
133                props |= VISUAL;
134            }
135            if c.infinite() {
136                props |= INFINITE;
137            }
138        }
139
140        props.into()
141    }
142
143    #[inline]
144    fn start(
145        &mut self,
146        sync_writer: &mut QWriter<SyncSignal>,
147        async_writer: &mut QWriter<AsyncSignal>,
148        state: &State,
149    ) -> Result<Signal> {
150        let mut news = vec![];
151        if self.children.is_empty() {
152            self.done = true;
153            sync_writer.push(SyncSignal::UpdateGraph);
154        } else {
155            for c in self.children.iter_mut() {
156                news.extend(c.start(sync_writer, async_writer, state)?);
157            }
158        }
159
160        Ok(news.into())
161    }
162
163    #[inline]
164    fn update(
165        &mut self,
166        signal: &ActionSignal,
167        sync_writer: &mut QWriter<SyncSignal>,
168        async_writer: &mut QWriter<AsyncSignal>,
169        state: &State,
170    ) -> Result<Signal> {
171        let mut done = vec![];
172        let mut news = vec![];
173        let mut finished = false;
174        for (i, c) in self.children.iter_mut().enumerate() {
175            if self.active[i] {
176                continue;
177            }
178
179            news.extend(c.update(signal, sync_writer, async_writer, state)?);
180
181            if c.is_over()? {
182                news.extend(c.stop(sync_writer, async_writer, state)?);
183                done.push(i);
184            }
185        }
186        for i in done.into_iter().rev() {
187            self.children[i] = Box::new(StatefulNil::default());
188            self.active[i] = false;
189        }
190        if self.active.iter().all(|&c| c) {
191            finished = true;
192        }
193
194        if finished {
195            self.done = true;
196        }
197
198        Ok(news.into())
199    }
200
201    fn show(
202        &mut self,
203        ui: &mut egui::Ui,
204        sync_writer: &mut QWriter<SyncSignal>,
205        async_writer: &mut QWriter<AsyncSignal>,
206        state: &State,
207    ) -> Result<()> {
208        let mut builder = StripBuilder::new(ui).size(Size::remainder());
209        for &p in self.proportions.iter() {
210            builder = builder.size(Size::relative(p));
211        }
212        builder = builder.size(Size::remainder());
213
214        match self.direction {
215            Direction::Horizontal => builder.horizontal(|mut strip| {
216                strip.empty();
217                for c in self.children.iter_mut() {
218                    strip.cell(|ui| {
219                        if let Err(e) = c.show(ui, sync_writer, async_writer, state) {
220                            sync_writer.push(SyncSignal::Error(e));
221                        }
222                    });
223                }
224                strip.empty();
225            }),
226            Direction::Vertical => builder.vertical(|mut strip| {
227                strip.empty();
228                for c in self.children.iter_mut() {
229                    strip.cell(|ui| {
230                        if let Err(e) = c.show(ui, sync_writer, async_writer, state) {
231                            sync_writer.push(SyncSignal::Error(e));
232                        }
233                    });
234                }
235                strip.empty();
236            }),
237        };
238
239        Ok(())
240    }
241
242    #[inline]
243    fn stop(
244        &mut self,
245        sync_writer: &mut QWriter<SyncSignal>,
246        async_writer: &mut QWriter<AsyncSignal>,
247        state: &State,
248    ) -> Result<Signal> {
249        let mut news = vec![];
250        for c in self.children.iter_mut() {
251            news.extend(c.stop(sync_writer, async_writer, state)?);
252        }
253        Ok(news.into())
254    }
255}