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}