cog_task/action/core/
view.rs1use crate::action::{Action, ActionSignal, Props, StatefulAction, DEFAULT, INFINITE, VISUAL};
2use crate::comm::{QWriter, Signal, SignalId};
3use crate::resource::{IoManager, ResourceAddr, ResourceManager};
4use crate::server::{AsyncSignal, Config, State, SyncSignal};
5use crate::util::f64_as_i64;
6use eframe::egui;
7use eyre::{eyre, Context, Result};
8use itertools::Itertools;
9use serde::{Deserialize, Serialize};
10use serde_cbor::Value;
11use std::collections::BTreeSet;
12
13#[derive(Debug, Deserialize, Serialize)]
14pub struct View {
15 #[serde(default)]
16 default: usize,
17 children: Vec<Box<dyn Action>>,
18 in_control: SignalId,
19}
20
21stateful!(View {
22 children: Vec<Box<dyn StatefulAction>>,
23 in_control: SignalId,
24 choice: usize,
25});
26
27impl Action for View {
28 #[inline]
29 fn in_signals(&self) -> BTreeSet<SignalId> {
30 let mut signals = BTreeSet::from([self.in_control]);
31 for c in self.children.iter() {
32 signals.extend(c.in_signals());
33 }
34 signals
35 }
36
37 #[inline]
38 fn out_signals(&self) -> BTreeSet<SignalId> {
39 let mut signals = BTreeSet::new();
40 for c in self.children.iter() {
41 signals.extend(c.out_signals());
42 }
43 signals
44 }
45
46 #[inline]
47 fn resources(&self, config: &Config) -> Vec<ResourceAddr> {
48 self.children
49 .iter()
50 .flat_map(|c| c.resources(config))
51 .unique()
52 .collect()
53 }
54
55 fn stateful(
56 &self,
57 io: &IoManager,
58 res: &ResourceManager,
59 config: &Config,
60 sync_writer: &QWriter<SyncSignal>,
61 async_writer: &QWriter<AsyncSignal>,
62 ) -> Result<Box<dyn StatefulAction>> {
63 let mut children = vec![];
64 for c in self.children.iter() {
65 children.push(c.stateful(io, res, config, sync_writer, async_writer)?);
66 }
67
68 Ok(Box::new(StatefulView {
69 done: false,
70 children,
71 in_control: self.in_control,
72 choice: self.default,
73 }))
74 }
75}
76
77impl StatefulAction for StatefulView {
78 impl_stateful!();
79
80 #[inline]
81 fn props(&self) -> Props {
82 self.children
83 .iter()
84 .fold(DEFAULT, |mut state, c| {
85 let c = c.props();
86 if c.visual() {
87 state |= VISUAL;
88 }
89 if c.infinite() {
90 state |= INFINITE;
91 }
92 state
93 })
94 .into()
95 }
96
97 #[inline]
98 fn start(
99 &mut self,
100 sync_writer: &mut QWriter<SyncSignal>,
101 async_writer: &mut QWriter<AsyncSignal>,
102 state: &State,
103 ) -> Result<Signal> {
104 self.choice = match state.get(&self.in_control) {
105 Some(Value::Integer(i)) => {
106 if *i < self.children.len() as i128 {
107 *i as usize
108 } else {
109 return Err(eyre!("Branch request is out of bounds."));
110 }
111 }
112 Some(Value::Float(x)) => {
113 let x = f64_as_i64(*x).wrap_err("Non-integer number supplied to view.")?;
114 if (0..self.children.len() as i64).contains(&x) {
115 x as usize
116 } else {
117 return Err(eyre!("Branch request is out of bounds."));
118 }
119 }
120 None => self.choice,
121 _ => return Err(eyre!("View control is in invalid state.")),
122 };
123
124 let mut news = vec![];
125 for c in self.children.iter_mut() {
126 news.extend(c.start(sync_writer, async_writer, state)?);
127 }
128
129 Ok(news.into())
130 }
131
132 #[inline]
133 fn update(
134 &mut self,
135 signal: &ActionSignal,
136 sync_writer: &mut QWriter<SyncSignal>,
137 async_writer: &mut QWriter<AsyncSignal>,
138 state: &State,
139 ) -> Result<Signal> {
140 if let ActionSignal::StateChanged(_, signal) = signal {
141 if signal.contains(&self.in_control) {
142 self.choice = match state.get(&self.in_control) {
143 Some(Value::Integer(i)) => {
144 if *i < self.children.len() as i128 {
145 *i as usize
146 } else {
147 return Err(eyre!("View request is out of bounds."));
148 }
149 }
150 Some(Value::Float(x)) => {
151 let x = f64_as_i64(*x).wrap_err("Non-integer number supplied to view.")?;
152 if (0..self.children.len() as i64).contains(&x) {
153 x as usize
154 } else {
155 return Err(eyre!("View request is out of bounds."));
156 }
157 }
158 None => self.choice,
159 _ => return Err(eyre!("View control is in invalid state.")),
160 };
161 }
162 }
163
164 let mut news = vec![];
165 for c in self.children.iter_mut() {
166 news.extend(c.update(signal, sync_writer, async_writer, state)?);
167 }
168
169 if self.children[self.choice].is_over()? {
170 self.done = true;
171 }
172
173 Ok(news.into())
174 }
175
176 fn show(
177 &mut self,
178 ui: &mut egui::Ui,
179 sync_writer: &mut QWriter<SyncSignal>,
180 async_writer: &mut QWriter<AsyncSignal>,
181 state: &State,
182 ) -> Result<()> {
183 self.children[self.choice].show(ui, sync_writer, async_writer, state)
184 }
185
186 #[inline]
187 fn stop(
188 &mut self,
189 sync_writer: &mut QWriter<SyncSignal>,
190 async_writer: &mut QWriter<AsyncSignal>,
191 state: &State,
192 ) -> Result<Signal> {
193 let mut news = vec![];
194 for c in self.children.iter_mut() {
195 news.extend(c.stop(sync_writer, async_writer, state)?);
196 }
197 Ok(news.into())
198 }
199}